Lesen Sie die Eingabe von raw_input (), ohne dass die schnelle Überschreibung durch andere Threads in Python überschrieben wurde

StackOverflow https://stackoverflow.com/questions/2082387

Frage

Ich versuche, die Benutzerbefehle mit RAW_Input () an einer Konsole einzugeben, dies funktioniert einwandfrei. Das Problem ist, dass ich Hintergrund-Threads habe, die gelegentlich eine Protokollinformation auf dem Bildschirm ausgeben, und wenn sie dies tun, durchfällt sie die Eingangsaufforderung (da der Ausgang überall hinweg der Cursor im Moment findet).

Dies ist ein kleines Python -Programm, das veranschaulicht, was ich meine.

#!/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

Dies ist ein Beispiel dafür, wie es aussehen könnte, wenn ich es ausführe:

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

Was ich möchte, ist, dass sich die Eingabeaufforderung zusammen mit der Ausgabe aus dem Thread bewegt. Like SO:

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> 

Irgendwelche Ideen, wie man dies erreicht, ohne auf hässliche Hacks zurückzugreifen? :)

War es hilfreich?

Lösung

Ich bin kürzlich auf dieses Problem gestoßen und möchte diese Lösung hier als zukünftige Referenz verlassen. Diese Lösungen löschen den anstehenden Text von RAW_Input (Readline) aus dem Terminal, drucken Sie den neuen Text und drucken dann an das Terminal, was im RAW_Input -Puffer war.

Dieses erste Programm ist ziemlich einfach, funktioniert aber nur korrekt, wenn nur 1 Textzeile auf RAW_Input wartet:

#!/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('> ')

Ausgabe:

$ ./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,

Die zweite verarbeitet korrekt 2 oder gepufferte Linien, weist jedoch mehr (Standard-) Modulabhängigkeiten auf und erfordert ein bisschen Terminalhackery:

#!/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('> ')

Ausgabe. Frühere Readline -Zeilen wurden richtig gelöscht:

$ ./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,

Nützliche Quellen:

So erhalten Sie Linux -Konsolenfensterbreite in Python

APT -ähnliche Spaltenausgabe - Python -Bibliothek(Dieses Code -Beispiel zeigt, wie Sie eine Terminalbreite für Unix oder Windows erhalten.)

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

Andere Tipps

Ich denke, Sie brauchen etwas, mit dem Sie Text dynamisch aus dem Terminalfenster drucken/löschen/überschreiben können, z. B. wie die Unix watch oder top Befehle funktionieren.

Ich denke, in Ihrem Fall würden Sie "Eingabeaufforderung>" drucken, aber wenn Sie dann eine "Hallo Welt" erhalten, überschreiben Sie "Eingabeaufforderung>" mit "Hallo Welt" und drucken Sie dann "Eingabeaufforderung>" in der folgenden Zeile. Ich glaube nicht, dass Sie das mit einem regelmäßigen Ausgangsdruck zum Terminal tun können.

Möglicherweise können Sie das tun, was Sie mit Python's möchten Flüche Bibliothek. Ich habe es nie verwendet, also kann ich Ihnen nicht sagen, wie Sie Ihr Problem lösen können (oder ob das Modul sogar Ihr Problem lösen kann), aber ich denke, es lohnt sich, einen Blick darauf zu werfen. Eine Suche nach "Python Curses Tutorial" lieferte a PDF -Tutorial -Dokument was hilfreich erscheint.

Sie müssen STDOut von einem einzelnen Thread nicht aus mehreren Threads aktualisieren ... oder Sie haben keine Kontrolle über verschachtelte E/A.

Sie möchten einen einzelnen Thread für das Schreiben von Ausgaben erstellen.

Sie können eine Warteschlange im Thread verwenden und alle anderen Threads ihre Ausgabeprotokollierungsinformationen darauf schreiben lassen. Lesen Sie dann aus dieser Warteschlange und schreiben Sie zu entsprechenden Zeiten zusammen mit Ihrer Eingabeaufforderung an stdout.

Ich denke nicht, dass es möglich ist. Wie sollte sich das überhaupt verhalten? Nichts wird angezeigt, bis der Benutzer eingegeben wird? Wenn dies der Fall ist, würde die Ausgabe nur dann kommen, wenn der Benutzer einen Befehl ausgibt (oder was auch immer Ihr System erwartet), und das klingt nicht wünschenswert.

Wenn Ihre Threads in eine andere Datei ausgegeben werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top