python 如何在while循环中获取用户输入而不阻塞
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1258566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get user input during a while loop without blocking
提问by Eric O Lebigot
I'm trying to write a while loop that constantly updates the screen by using os.system("clear") and then printing out a different text message every few seconds. How do I get user input during the loop? raw_input() just pauses and waits, which is not the functionality I want.
我正在尝试编写一个 while 循环,通过使用 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)
I would like to be able to press 'q' or 'p' in the middle to quit and pause respectively.
我希望能够按中间的“q”或“p”分别退出和暂停。
回答by Alex Martelli
The selectmodule in Python's standard library may be what you're looking for -- standard input has FD 0, though you may also need to put a terminal in "raw" (as opposed to "cooked") mode, on unix-y systems, to get single keypresses from it as opposed to whole lines complete with line-end. If on Windows, msvcrt, also in Python standard library, has all the functionality you need -- msvcrt.kbhit()
tells you if any keystroke is pending, and, if so, msvcrt.getch()
tells you what character it is.
Python 标准库中的select模块可能就是你要找的——标准输入有 FD 0,但你可能还需要在 unix-y 上将终端置于“原始”(而不是“熟”)模式系统,从中获得单个按键,而不是完整的行尾。如果在 Windows 上,同样在 Python 标准库中的msvcrt具有您需要的所有功能——msvcrt.kbhit()
告诉您是否有任何按键未决,如果是,则msvcrt.getch()
告诉您它是什么字符。
回答by Eric O Lebigot
You can also check one of the recipesavailable out there, which gives you the functionality you're looking for for both Unix and Windows.
您还可以查看可用的方法之一,它为您提供了您正在寻找的 Unix 和 Windows 功能。
回答by e-satis
You can do that with threads, here is a basic example :
你可以用线程来做到这一点,这是一个基本的例子:
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()
As usual, using threads is tricky, so be sure you understand what you do before coding that.
像往常一样,使用线程很棘手,因此请确保在编码之前了解您所做的工作。
Warning : Queue will be rename in queue in Python 3.
警告:队列将在 Python 3 中的队列中重命名。