Python

2010-01-17 19 views
11

में अन्य थ्रेड द्वारा त्वरित ओवरराइट किए बिना raw_input() से इनपुट पढ़ना मैं कच्चे_इनपुट() का उपयोग कर कंसोल पर उपयोगकर्ता इनपुट कमांड को देने की कोशिश कर रहा हूं, यह ठीक काम करता है। समस्या यह है कि मेरे पास पृष्ठभूमि धागे हैं जो कभी-कभी स्क्रीन पर लॉग-सूचना आउटपुट करते हैं और जब वे करते हैं तो वे इनपुट प्रॉम्प्ट को गड़बड़ कर देते हैं (क्योंकि आउटपुट जहां भी कर्सर इस समय होता है)।Python

यह एक छोटा पायथन प्रोग्राम है जो मुझे बताता है कि मेरा क्या मतलब है।

Prompt> Hello World 
Hello World 
Hello World 
Hello World 
test 
You typed test 
Prompt> Hello World 
Hello World 
Hello World 
hellHello World 
o 
You typed hello 
Prompt> Hello World 
Hello World 
Hello World 
Hello World 

क्या मैं चाहता हूँ शीघ्र धागे से उत्पादन के साथ स्थानांतरित करने के लिए के लिए है:

#!/usr/bin/env python 
import threading 
import time 

def message_loop(): 
    while True: 
     time.sleep(1) 
     print "Hello World" 

thread = threading.Thread(target = message_loop) 
thread.start() 

while True: 
    input = raw_input("Prompt> ") 
    print "You typed", input 

यह यह कैसा जब मैं इसे चलाने के देख सकता का एक उदाहरण है। इस तरह:

Hello World 
Hello World 
Prompt> test 
You typed test 
Hello World 
Hello World 
Hello World 
Hello World 
Hello World 
Prompt> hello 
You typed hello 
Hello World 
Hello World 
Hello World 
Hello World 
Prompt> 

बदसूरत हैक का उपयोग किए बिना इसे कैसे प्राप्त किया जाए इस पर कोई विचार? :)

उत्तर

23

मुझे हाल ही में इस समस्या का सामना करना पड़ा, और भविष्य में संदर्भ के लिए यह समाधान यहां छोड़ना चाहूंगा। ये समाधान टर्मिनल से लंबित कच्चे_इनपुट (रीडलाइन) टेक्स्ट को साफ़ करते हैं, नए टेक्स्ट को प्रिंट करते हैं, फिर कच्चे_इनपुट बफर में टर्मिनल पर पुनर्मुद्रण करते हैं।

यह पहला कार्यक्रम बहुत सरल है, लेकिन केवल सही ढंग से काम करता है जब वहाँ raw_input के लिए इंतज़ार कर पाठ का केवल 1 पंक्ति:

#!/usr/bin/python 

import time,readline,thread,sys 

def noisy_thread(): 
    while True: 
     time.sleep(3) 
     sys.stdout.write('\r'+' '*(len(readline.get_line_buffer())+2)+'\r') 
     print 'Interrupting text!' 
     sys.stdout.write('> ' + readline.get_line_buffer()) 
     sys.stdout.flush() 

thread.start_new_thread(noisy_thread,()) 
while True: 
    s = raw_input('> ') 

आउटपुट:

$ ./threads_input.py 
Interrupting text! 
Interrupting text! 
Interrupting text! 
> WELL, PRINCE, Genoa and Lucca are now no more than private estates of the Bo 
Interrupting text! 
> WELL, PRINCE, Genoa and Lucca are now no more than private estates of the Bo 
naparte family. No, I warn you, that if you do not tell me we are at war, 

दूसरा सही ढंग से 2 या अधिक संभालती है buffered लाइनें, लेकिन अधिक (मानक) मॉड्यूल निर्भरता है और टर्मिनल हैकरी के बहुत कम की आवश्यकता है:

#!/usr/bin/python 

import time,readline,thread 
import sys,struct,fcntl,termios 

def blank_current_readline(): 
    # Next line said to be reasonably portable for various Unixes 
    (rows,cols) = struct.unpack('hh', fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ,'1234')) 

    text_len = len(readline.get_line_buffer())+2 

    # ANSI escape sequences (All VT100 except ESC[0G) 
    sys.stdout.write('\x1b[2K')       # Clear current line 
    sys.stdout.write('\x1b[1A\x1b[2K'*(text_len/cols)) # Move cursor up and clear line 
    sys.stdout.write('\x1b[0G')       # Move to start of line 


def noisy_thread(): 
    while True: 
     time.sleep(3) 
     blank_current_readline() 
     print 'Interrupting text!' 
     sys.stdout.write('> ' + readline.get_line_buffer()) 
     sys.stdout.flush()   # Needed or text doesn't show until a key is pressed 


if __name__ == '__main__': 
    thread.start_new_thread(noisy_thread,()) 
    while True: 
     s = raw_input('> ') 

आउटपुट। पिछला ReadLine लाइनों को ठीक से मंजूरी दे दी:

$ ./threads_input2.py 
Interrupting text! 
Interrupting text! 
Interrupting text! 
Interrupting text! 
> WELL, PRINCE, Genoa and Lucca are now no more than private estates of the Bo 
naparte family. No, I warn you, that if you do not tell me we are at war, 

उपयोगी स्रोत:

How to get Linux console window width in Python

apt like column output - python library (इस कोड नमूना दिखाता है कि या तो यूनिक्स या Windows के लिए टर्मिनल चौड़ाई प्राप्त करने के लिए)

http://en.wikipedia.org/wiki/ANSI_escape_code

+0

यह वही है जो मैं खोज रहा था। धन्यवाद :) – Jim

+1

['आशीर्वाद 'मॉड्यूल] (https://pypi.python.org/pypi/blessings/) आउटपुट को प्रारूपित करने और टर्मिनल के गले में बहुत गहराई तक पहुंचने के बिना चारों ओर स्थानांतरित करने की अनुमति देता है। – jfs

+0

सावधान रहें, कुछ पायथन संस्करणों पर सावधान रहें यदि टर्मिनल का आकार 'रीडलाइन' मॉड्यूल में बग के कारण रनटाइम के दौरान बदल दिया गया है जो टर्मिनल आकार बदलने की घटनाओं को अनदेखा कर देता है (इसलिए यह उसके आंतरिक बफर का आकार बदलता नहीं है और यह कॉलम को तोड़ता है -काउंटिंग तर्क)। Https://bugs.python.org/issue23735 देखें। यह सौभाग्य से पाइथन 3.5 में तय किया गया प्रतीत होता है। किक-गधे अन्यथा जवाब :) – Thomas

0

मुझे नहीं लगता कि यह संभव है। वैसे भी यह कैसे व्यवहार करना चाहिए? जब तक उपयोगकर्ता एंटर दबाता है तब तक कुछ भी दिखाई नहीं देता है? यदि ऐसा है, तो आउटपुट केवल तभी आएगा जब उपयोगकर्ता कमांड जारी करेगा (या जो भी आपकी प्रणाली अपेक्षा करता है), और यह वांछनीय नहीं लगता है।

मेथिंक आपके धागे को दूसरी फ़ाइल में आउटपुट करना चाहिए।

+0

नहीं, मैं उपयोगकर्ता को एंटर दबाए जाने से पहले संदेश दिखाना चाहता हूं। लेकिन संकेत संदेश से ओवरराइट नहीं होने के लिए बस नीचे चलेगा। – Jim

3

मुझे लगता है कि आपको ऐसा कुछ चाहिए जो आपको टर्मिनल विंडो से टेक्स्ट को गतिशील रूप से प्रिंट/हटा/ओवरराइट करने देता है। यूनिक्स watch या top आदेश कैसे काम करते हैं।

मुझे लगता है कि आपके मामले में आप "प्रॉम्प्ट>" प्रिंट करेंगे, लेकिन फिर जब आपको "हैलो वर्ल्ड" मिलता है तो आप "हैलो वर्ल्ड" के साथ "प्रॉम्प्ट>" ओवरराइट करते हैं, और फिर नीचे दी गई रेखा पर "प्रॉम्प्ट>" प्रिंट करते हैं। मुझे नहीं लगता कि आप टर्मिनल को नियमित आउटपुट प्रिंटिंग के साथ ऐसा कर सकते हैं।

आप पाइथन की curses लाइब्रेरी का उपयोग करके जो भी करना चाहते हैं वह करने में सक्षम हो सकते हैं। मैंने इसका कभी भी उपयोग नहीं किया है, इसलिए मैं आपको यह नहीं बता सकता कि आपकी समस्या का समाधान कैसे करें (या यदि मॉड्यूल भी आपकी समस्या का समाधान करने में सक्षम होगा), लेकिन मुझे लगता है कि यह देखने में लायक है। "पायथन श्राप ट्यूटोरियल" की खोज ने PDF tutorial document प्रदान किया जो उपयोगी लगता है।

+0

मुझे अतिरिक्त निर्भरता नहीं होगी। लेकिन चूंकि यह केवल एक कॉस्मेटिक बदलाव है। मुझे लगता है कि मुझे शापों पर एक नज़र डालेंगी और यदि वर्तमान में मौजूद नहीं है तो वर्तमान व्यवहार पर वापस आना :) :) – Jim

1

आपको एकाधिक धागे से नहीं, एक थ्रेड से stdout अद्यतन करने की आवश्यकता है ... या फिर आपके पास interleaved i/o पर कोई नियंत्रण नहीं है।

आप आउटपुट लेखन के लिए एक एकल धागा बनाना चाहते हैं।

आप धागे में एक कतार का उपयोग कर सकते हैं और अन्य सभी धागे अपनी आउटपुट लॉगिंग जानकारी लिख सकते हैं .. फिर इस कतार से पढ़ें और अपने त्वरित संदेश के साथ उचित समय पर stdout पर लिखें।

+1

अन्य धागे से आने वाले आउटपुट को लगातार तरीके से संभाला जाता है, जो एक दूसरे के साथ अंतःस्थापित नहीं होता है। यह इनपुट है कि समस्या है। एक कतार का उपयोग करना, और इनपुट और आउटपुट दोनों के लिए एक धागा मुझे लगता है कि मुझे अपना इनपुट हैंडलिंग लागू करना होगा। raw_input वर्तमान में ईओएल तक सक्रिय धागा को अवरुद्ध करता है। – Jim