如何在循环中非阻塞地获取用户输入
我正在尝试写一个循环,这个循环会不断更新屏幕,方法是使用 os.system("clear") 来清屏,然后每隔几秒打印出不同的文本信息。可是我想在这个循环中获取用户输入,像 raw_input() 这样的函数会让程序暂停并等待输入,这不是我想要的功能。
import os
import time
string = "the fox jumped over the lazy dog"
words = string.split(" ")
i = 0
while 1:
os.system("clear")
print words[i]
time.sleep(1)
i += 1
i = i%len(words)
我希望能够在循环中按 'q' 来退出,或者按 'p' 来暂停。
3 个回答
2
你可以通过线程来实现这个功能,下面是一个简单的例子:
import threading, os, time, itertools, Queue
# setting a cross platform getch like function
# thks to the Python Cookbook
# why isn't standard on this battery included language ?
try : # on windows
from msvcrt import getch
except ImportError : # on unix like systems
import sys, tty, termios
def getch() :
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try :
tty.setraw(fd)
ch = sys.stdin.read(1)
finally :
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
# this will allow us to communicate between the two threads
# Queue is a FIFO list, the param is the size limit, 0 for infinite
commands = Queue.Queue(0)
# the thread reading the command from the user input
def control(commands) :
while 1 :
command = getch()
commands.put(command) # put the command in the queue so the other thread can read it
# don't forget to quit here as well, or you will have memory leaks
if command == "q" :
break
# your function displaying the words in an infinite loop
def display(commands):
string = "the fox jumped over the lazy dog"
words = string.split(" ")
pause = False
command = ""
# we create an infinite generator from you list
# much better than using indices
word_list = itertools.cycle(words)
# BTW, in Python itertools is your best friend
while 1 :
# parsing the command queue
try:
# false means "do not block the thread if the queue is empty"
# a second parameter can set a millisecond time out
command = commands.get(False)
except Queue.Empty, e:
command = ""
# behave according to the command
if command == "q" :
break
if command == "p" :
pause = True
if command == "r" :
pause = False
# if pause is set to off, then print the word
# your initial code, rewritten with a generator
if not pause :
os.system("clear")
print word_list.next() # getting the next item from the infinite generator
# wait anyway for a second, you can tweak that
time.sleep(1)
# then start the two threads
displayer = threading.Thread(None, # always to None since the ThreadGroup class is not implemented yet
display, # the function the thread will run
None, # doo, don't remember and too lazy to look in the doc
(commands,), # *args to pass to the function
{}) # **kwargs to pass to the function
controler = threading.Thread(None, control, None, (commands,), {})
if __name__ == "__main__" :
displayer.start()
controler.start()
像往常一样,使用线程是有点复杂的,所以在开始编写代码之前,一定要确保你理解你在做什么。
注意:在Python 3中,Queue会被改名为queue。
3
你还可以看看这里的一个示例,它提供了你需要的功能,适用于Unix和Windows系统。