Python如何读取Unicode标准输入流而不进行批处理

3

如果我在Python中从标准输入读取输入,那么for循环将在循环体运行之前收集多行(至少在cpython中是这样)。

from __future__ import print_function
import sys

for line in sys.stdin:
    print("Echo:", line.strip())

输出:

$ python ../test.py 
foo
bar
Echo: foo
Echo: bar

文本行通常以批量方式处理。我可以通过以下方式避免:

from __future__ import print_function
import sys

for line in iter(sys.stdin.readline, ''):
    print("Echo:", line.strip())

输出:

$ python ../test.py 
foo
Echo: foo
bar
Echo: bar

这正是我需要的。

我的问题是,我必须阅读UTF-8输入,但使用iter()codecs.getwriter中不起作用。

from __future__ import print_function
import sys
import codecs

sys.stdin = codecs.getreader('utf-8')(sys.stdin)
for line in iter(sys.stdin.readline, ''):
    print("Echo:", line.strip())

$ python ../test.py 
foo
bar
Echo: foo
Echo: bar

有没有办法在从stdin读取utf8数据时避免批处理?
< p>编辑: 为完整性添加了导入语句。


我尝试了你的第一个示例,但它并没有像你描述的那样“批处理”。你使用的是什么系统? - tdelaney
Python 2.x应该在控制台运行时为您解决编码问题。print sys.stdin.encoding会输出什么? - tdelaney
第一个在Python2.7下运行的程序并没有产生你所声称的输出。(它打印出了 ('Echo:', 'foo')。)你实际上使用的是哪个版本的Python? - Robᵩ
我在Ubuntu 12.04LTS上使用Python 2.7.3时遇到了这种情况。 - bwj
2.7.3 (默认, 2014年2月27日, 19:58:35) [GCC 4.6.3] 这是sys.version的精确输出。 - bwj
@Robᵩ 的示例中缺少导入,具体来说是 from __future__ import print_function,抱歉。 - bwj
2个回答

2

使用lambda

for line in iter(lambda: sys.stdin.readline().decode('utf-8'), ''):
    print 'Echo:', line.strip()

或者,在循环体中解码:

for line in iter(sys.stdin.readline, ''):
    print "Echo:", line.decode('utf-8').strip()

我不明白!特别是当我们不知道 OP 的控制台采用什么编码方式时,这怎么解决问题? - tdelaney
@tdelaney,OP在他/她的代码中指定了utf-8 - falsetru
@tdelaney,因为iter会调用sys.stdin.readline直到遇到一个空行。http://asciinema.org/a/12470 - falsetru

1
你应该使用 raw_input 来从 stdin 中获取一行输入。
try:
    while True:
        print("Echo:", raw_input())
except EOFError:
    pass

问题在于Python 2只有这种缓冲方式。请参阅manpage上-u的文档。
-u   Force  stdin,  stdout  and stderr to be totally unbuffered.  On systems
     where it matters, also put stdin, stdout and  stderr  in  binary  mode.
     Note  that there is internal buffering in xreadlines(), readlines() and
     file-object iterators ("for line in sys.stdin") which is not influenced
     by   this   option.   To  work  around  this,  you  will  want  to  use
     "sys.stdin.readline()" inside a "while 1:" loop.

重要的部分是使用sys.stdin.readline()是推荐的做法;强制取消缓冲文件对象的好方法不太可能存在。
你应该在获取每行时只需解码即可。

无缓冲模式如何解决问题? - tdelaney
@falsetru 是的,print 函数让我感到困惑。谢谢,这使得原因更加明显。不幸的是,我意识到我也错了。 - Veedrac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接