如何在不等待输入的情况下检查潜在的空stdin?

2024-06-26 16:40:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图在不等待输入的情况下读取键盘输入。目的是在“无限”循环中使用正确:。在

到目前为止,我一直在尝试操作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")

Tags: 目的pypisettingsdefstdinsys情况current
1条回答
网友
1楼 · 发布于 2024-06-26 16:40:00

最终作为Python文件对象基础的POSIX I/O函数有两种不同的模式,blocking和non-blocking,由一个名为^{}的标志控制。尤其是,^{}函数表示:

When attempting to read a file … that … has no data currently available … If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].

在Python中,^{}模块中可以使用此标志。在


sys.stdin已经打开,所以您不能将O_NONBLOCK传递给os.open函数,那么……您要做什么?实际上,你可能想打开/dev/tty;这取决于你实际在做什么。在这种情况下,答案是显而易见的。但是假设你没有,所以你想改变已经打开的文件的标志。这正是^{}的用途。使用F_GETFL操作来读取当前标志,或读取O_NONBLOCK的位,并F_SETFL结果。当然,如果您想恢复内容,您可以记住当前的标志以便以后使用。在

在Python中,fcntl函数和操作常量可在^{}模块中使用。在


最后一个问题:sys.stdin不是一个原始文件对象,而是一个在^{}之上执行Unicode解码的^{},它本身在^{}之上添加了缓冲。因此,sys.stdin.read()没有直接调用POSIX read函数。为此,您需要使用sys.stdin.buffer.raw。如果您想在原始输入和正常输入之间来回切换,可能还需要进行大量仔细的刷新。(请注意,这意味着您将放弃Unicode,而是得到一个单字节的bytes对象,它可以是,例如,UTF-8字符的一半,或者是终端转义字符的四分之一。希望你能预料到。)


现在,FileIO.read在没有可用的情况下返回什么?它是RawIOBase的一个实现,^{}说:

If 0 bytes are returned, and size was not 0, this indicates end of file. If the object is in non-blocking mode and no bytes are available, None is returned.

换句话说,如果没有可用的,您将得到None,对于EOF,b'',对于其他任何东西,您将得到一个单字节{}。在


所以,把它们放在一起:

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)

最后一件事:有没有一种方法可以在不读的情况下判断输入是否准备就绪?是的,但不是便携的。根据您的平台,selectpollepoll和/或{}可能可用,并且可以处理常规文件。read(0)可以保证返回b'',而不是{}。等等。您可以阅读本地手册页。但是一个更简单的解决方案与C的stdio相同:添加一个1字节的最大缓冲区,并使用它来实现您自己的read和{}或{}和{}包装。在

相关问题 更多 >