在raw_input()之前刷新Python输入

2 投票
1 回答
7359 浏览
提问于 2025-04-18 12:10

作为一个刚接触操作系统和命令行的PHP程序员,我发现Python中用户输入的内容似乎都是先被暂时存储起来,等到第一次使用raw_input的时候再一起输出,这让我感到很惊讶。

我找到了一些代码,可以在调用raw_input之前使用,这似乎能在osX上“解决”这个问题,虽然据说它是提供了对Windows功能的访问:

class FlushInput(object):

    def flush_input(self):
        try:
            import msvcrt
            while msvcrt.kbhit():
                msvcrt.getch()
        except ImportError:
            import sys, termios
            termios.tcflush(sys.stdin, termios.TCIOFLUSH)

我理解得对吗?stdin、stdout和stderr这些方法在不同的操作系统上会有所不同吗?

我想,也许像Django这样的框架有内置的方法可以简化交互,但基本上是不是只需要几行代码就能告诉Python“在被邀请之前不要接受任何输入?”

1 个回答

5

啊,如果我理解得没错(当然我还需要进一步理解),答案是:是的,stdin, stdout, stderr,也就是“标准”输入、输出和错误流,它们的处理方式可能会因操作系统的不同而有所不同,因为这些是操作系统的产物,而不是某种特定的编程语言。

我们通常认为“让python忽略stdin,直到需要输入”为自动化的想法,源于把“终端”想象成打字机。打字机的目标是将信息以人类可读的格式记录下来,而终端的目标是传输信息,这些信息最终会被转换为机器可读的格式,并返回人类可读的响应。

我们现在所理解的“终端”,实际上是对一种叫做终端的物理机器的虚拟重现,这种机器曾经是将数据输入到计算机处理器和从中读取数据的方法,对吧?而文本编辑器则是一个应用程序,它利用键盘、显示器和操作系统及其库的处理能力,创造出一个虚拟的打字机。

像mac OS终端这样的应用程序,甚至我们通过ssh连接与另一台服务器交互时使用的tty,实际上是在创建一个虚拟终端,通过它我们可以与处理器进行交互,发送信息到stdin,并从stdout和stderr接收信息。当我们在终端屏幕上输入的字母出现时,是因为这些字母被“回显”到终端窗口中。

所以没有理由期待python或其他任何语言与终端之间的关系,默认情况下会阻止来自终端的输入流。

上面的代码使用了python的异常处理,提供了两种在程序执行某些操作之前清空输入流的替代方法。在OSX平台上,代码:

import sys, termios
termios.tcflush(sys.stdin, termios.TCIOFLUSH)

导入系统,以便我们可以访问stdin和termios,这是python用于管理POSIX(LINUX、UNIX)应用程序的模块,实际上管理着两个虚拟终端——一个是它自己和用户之间的,另一个是它自己和操作系统之间的。tcflush似乎是一个接受至少两个参数的函数——第一个是要清空的流,即文件描述符(fd),第二个是要清空的队列。我不太确定在这种情况下文件描述符和队列之间的区别,可能是fd包含尚未添加到队列中的数据,而队列包含不再在fd中的数据。

msvcrt是用于与Windows版本的终端进行交互(管理)的python模块,我想msvcrt.kbhit()msvcrt.getch()是用于清空其输入队列的函数。

UNIX和Windows的函数调用可以互换,这样我们就可以先尝试UNIX的方式,而不是先用Windows的方式,如果出现ImportError错误,再用Windows的方式:

class FlushInput(object):

    def flush_input(self):
        try:
            import sys, termios
            termios.tcflush(sys.stdin, termios.TCIOFLUSH)
        except ImportError:
            import msvcrt
            while msvcrt.kbhit():
                msvcrt.getch()

这里有一个termios的介绍,帮助澄清了这个过程。

撰写回答