如果输入不是数字,我有以下Python脚本读取数字并输出错误。
import fileinput
import sys
for line in (txt.strip() for txt in fileinput.input()):
if not line.isdigit():
sys.stderr.write("ERROR: not a number: %s\n" % line)
如果我从stdin获得输入,我必须按 Ctrl + D 两次来结束程序。为什么呢?
当我自己运行Python解释器时,我只需要按 Ctrl + D 。
bash $ python test.py
1
2
foo
4
5
<Ctrl+D>
ERROR: not a number: foo
<Ctrl+D>
bash $
答案 0 :(得分:14)
在Python 3中,这是由a bug in Python's standard I/O library引起的。该错误已在Python 3.3中修复。
在Unix终端中,键入Ctrl + D实际上并不关闭进程的stdin。但是输入Enter或Ctrl + D确实会导致OS read
系统调用立即返回。所以:
>>> sys.stdin.read(100)
xyzzy (I press Enter here)
(I press Ctrl+D once)
'xyzzy\n'
>>>
sys.stdin.read(100)
被委托给sys.stdin.buffer.read
,它在循环中调用系统read(),直到它累积完整请求的数据量;或者系统read()返回0个字节;或者发生错误。 (docs) (source)
在第一行之后按Enter键导致系统read()返回6个字节。 sys.stdin.buffer.read
再次调用read()以尝试获取更多输入。然后我按下Ctrl + D,导致read()返回0个字节。此时,sys.stdin.buffer.read
放弃并返回它之前收集的6个字节。
请注意,该进程仍然在stdin上有我的终端,我仍然可以输入内容。
>>> sys.stdin.read() (note I can still type stuff to python)
xyzzy (I press Enter)
(Press Ctrl+D again)
'xyzzy\n'
行。当这个问题最初被问到时,这是被破坏的部分。它现在有效。但在Python 3.3之前,存在一个错误。
这个错误有点复杂 - 基本上问题是两个独立的层正在做同样的工作。编写BufferedReader.read()
以反复调用self.raw.read()
,直到它返回0个字节。但是,原始方法FileIO.read()
执行了自己的循环 - 直到零字节。因此,第一次在Python中按Ctrl + D时会出现此错误,这会导致FileIO.read()
返回6个字节到BufferedReader.read()
,然后会立即再次调用self.raw.read()
。第二个Ctrl + D会导致 返回0个字节,然后BufferedReader.read()
最终会退出。
遗憾的是,这种解释比我之前的解释要长得多,但它具有正确的优点。虫子就像那样......
答案 1 :(得分:9)
这很可能与Python有以下Python问题有关:
答案 2 :(得分:4)
我在回答这个问题时写了一个解释。
How to capture Control+D signal?
简而言之,终端上的Control-D只会使终端刷新输入。这使得read
系统调用返回。它第一次返回非零值(如果你键入的东西)。第二次,它返回0,这是“文件结束”的代码。
答案 3 :(得分:0)
第一次认为它是输入时,第二次保持输入!
这仅在输入来自tty时发生。可能是因为终端设置缓冲了字符,直到输入换行符(回车符)。
答案 4 :(得分:0)
使用“for file in file:”形式从文件中读取行,Python使用隐藏的预读缓冲区(请参阅file.next函数中的http://docs.python.org/2.7/library/stdtypes.html#file-objects)。首先,这解释了为什么在读取每个输入行时写入输出的程序在按CTRL-D之前不显示输出。其次,为了给用户一些控制缓冲,按CTRL-D将输入缓冲区刷新到应用程序代码。当输入缓冲区为空时按CTRL-D将被视为EOF。
将这个联系在一起回答原始问题。输入一些输入后,第一个ctrl-D(单独一行)刷新应用程序代码的输入。现在缓冲区为空,第二个ctrl-D充当文件结束(EOF)。
file.readline()
不会出现此行为。