我试图从键盘输入读取而不等待输入。目的是在无限的"循环ala而True:。
到目前为止,我一直试图操纵readchar库https://pypi.python.org/pypi/readchar/0.6,但没有运气。虽然它不等待Enter,但它仍然等待一些输入。我不希望它等待输入,而只是检查并返回""如果没有输入,则为一些占位符。
以下是我一直在使用的内容:
def readchar():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
def main():
while True:
current = readchar()
if current == "some letter":
print("things happen")
答案 0 :(得分:3)
最终构成Python文件对象的POSIX I / O函数有两种不同的模式,阻塞和非阻塞,由一个名为O_NONBLOCK
的标志控制。特别是,read
函数说:
尝试读取文件时......当前没有数据...如果设置了
O_NONBLOCK
, read()将返回-1并设置 errno 到[EAGAIN]
。
在Python中,os
模块中提供了此标志。
sys.stdin
已经打开,因此您无法将O_NONBLOCK
传递给os.open
函数,所以......你做了什么?好吧,你实际上可能想要打开/dev/tty
;这取决于你实际在做什么。在那种情况下,答案是显而易见的。但是我们假设你没有。因此,您想要更改已打开文件的标志。这正是fcntl
的用途。您可以使用F_GETFL
操作来读取当前标志,或者使用O_NONBLOCK
的位和F_SETFL
结果。当然,如果你想要恢复,你可以记住当前的标志。
在Python中,fcntl
模块中提供了sys.stdin
函数和操作常量。
最后一个问题:sys.stdin.read()
不是原始文件对象,它是fcntl
,它在TextIOWrapper
之上进行Unicode解码,它本身在BufferedReader
之上添加缓冲。 {3}}。因此,read
不直接调用POSIX sys.stdin.buffer.raw
函数。为此,您需要使用bytes
。如果你想在原始输入和正常输入之间来回切换,你可能还需要进行大量的小心刷新。 (注意,这意味着你放弃了Unicode,而是获得了一个单字节FileIO.read
对象,例如,可能是UTF-8字符的一半或终端转义字符的四分之一。希望你'期待那样。)
现在,RawIOBase
什么都没有可用时返回?嗯,这是None
的实现,FileIO
说:
如果返回0个字节,且size不为0,则表示文件结束。如果对象处于非阻塞模式且没有可用字节,则返回
None
。
换句话说,如果没有可用内容,您将获得b''
,对于EOF,您将获得bytes
,或者为其他任何内容获得单字节old_settings = termios.tcgetattr(fd)
old_flags = fcntl.fcntl(fd, fcntl.F_GETFL)
try:
tty.setraw(fd)
fcntl.fcntl(fd, fcntl.F_SETFL, old_flags | os.O_NONBLOCK)
return sys.stdin.buffer.raw.read(1)
finally:
fcntl.fcntl(fd, fcntl.F_SETFL, old_flags)
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
。
所以,把它们放在一起:
select
最后一件事:有没有办法告诉输入是否准备就绪而不阅读它?是的,但不是便携式的。根据您的平台,poll
,epoll
,kqueue
和/或read(0)
可能可用,并且可能适用于常规文件。 b''
可以保证None
而不是read
。等等。您可以阅读本地手册页。但更简单的解决方案与C的stdio相同:添加1字节最大缓冲区,并使用它来实现自己的peek
和read
或unread
和{{1}包装。