从raw_input()读取输入,而提示没有被Python中的其他线程覆盖 [英] Reading input from raw_input() without having the prompt overwritten by other threads in Python
问题描述
我试图让用户使用raw_input()在控制台上输入命令,这很好.问题是我有一些后台线程,偶尔将日志信息输出到屏幕上,并且当他们这样做时,它们会弄乱输入提示(因为输出到了当前光标所在的位置).
I'm trying to let the user input commands at a console using raw_input(), this works fine. The problem is I have background threads that occasionally output log-information to the screen and when they do they mess up the input prompt (since the output go wherever the cursor happens to be at the moment).
这是一个小的Python程序,可以说明我的意思.
This is a small Python program that illustrate what i mean.
#!/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
这是当我运行它时的外观示例:
This is an example of what it could look like when I run it:
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
我想要的是提示与线程的输出一起移动.像这样:
What I want is for the prompt to move along with the output from the thread. 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>
关于如何在不使用丑陋的黑客手段的情况下实现这一目标的任何想法? :)
Any ideas on how to achieve this without resorting to ugly hacks? :)
推荐答案
我最近遇到了此问题,并希望将此解决方案留在此处以供将来参考. 这些解决方案从终端清除待处理的raw_input(readline)文本,打印新文本,然后将raw_input缓冲区中的内容重新打印到终端.
I recently encountered this problem, and would like to leave this solution here for future reference. These solutions clear the pending raw_input (readline) text from the terminal, print the new text, then reprint to the terminal what was in the raw_input buffer.
第一个程序非常简单,但是只有在只有一行文本等待raw_input时,它才能正确运行:
This first program is pretty simple, but only works correctly when there is only 1 line of text waiting for raw_input:
#!/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条或更多的缓冲行,但是具有更多(标准)模块依赖项,并且需要一点点终端黑客攻击:
The second correctly handles 2 or more buffered lines, but has more (standard) module dependencies and requires a wee bit of terminal hackery:
#!/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行已正确清除:
Output. Previous readline lines cleared properly:
$ ./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,
有用的资料来源:
Useful sources:
像列输出一样易于使用-python库 (此代码示例显示了如何获取Unix或Windows的终端宽度)
apt like column output - python library (This code sample shows how to get terminal width for either Unix or Windows)
http://en.wikipedia.org/wiki/ANSI_escape_code
这篇关于从raw_input()读取输入,而提示没有被Python中的其他线程覆盖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!