[英]Python 2 to 3 conversion: iterating over lines in subprocess stdout
我有以下Python 2示例代码,我想与Python 3兼容:
call = 'for i in {1..5}; do sleep 1; echo "Hello $i"; done'
p = subprocess.Popen(call, stdout=subprocess.PIPE, shell=True)
for line in iter(p.stdout.readline, ''):
print(line, end='')
这在Python 2中运行良好,但在Python 3中, p.stdout
不允许我指定编码并且读取它将返回字节字符串而不是Unicode,因此与''
的比较将始终返回false并且iter
将不会停止。 这个问题似乎暗示在Python 3.6中有一种定义这种编码的方法。
现在,我已经将iter
调用更改为当它找到一个空字节字符串iter(p.stdout.readline, b'')
时停止,这似乎在2和3中工作。我的问题是:这两个都安全吗?和3? 有没有更好的方法来确保兼容性?
注意:我没有for line in p.stdout:
使用for line in p.stdout:
因为我需要在生成时打印每一行,根据这个答案 p.stdout
有一个太大的缓冲区。
您可以添加unversal_newlines=True
。
p = subprocess.Popen(call, stdout=subprocess.PIPE, shell=True, universal_newlines=True)
for line in iter(p.stdout.readline, ''):
print(line, end='')
而不是bytes
,将返回str
因此''
将在两种情况下都有效。
以下是文档对该选项的说法:
如果universal_newlines为False,则文件对象stdin,stdout和stderr将作为二进制流打开,并且不会进行行结束转换。
如果universal_newlines为True,则这些文件对象将使用locale.getpreferredencoding(False)返回的编码以通用换行模式打开为文本流。 对于stdin,输入中的行结束字符'\\ n'将转换为默认行分隔符os.linesep。 对于stdout和stderr,输出中的所有行结尾都将转换为'\\ n'。 有关更多信息,请参阅io.TextIOWrapper类的文档,当其构造函数的换行参数为None时。
它没有明确地提到bytes
与str
区别,但是通过声明False
返回二进制流并且True
返回文本流来暗示它。
你可以使用p.communicate()
然后解码它,如果它是一个bytes
对象:
from __future__ import print_function
import subprocess
def b(t):
if isinstance(t, bytes):
return t.decode("utf8")
return t
call = 'for i in {1..5}; do sleep 1; echo "Hello $i"; done'
p = subprocess.Popen(call, stdout=subprocess.PIPE, shell=True)
stdout, stderr = p.communicate()
for line in iter(b(stdout).splitlines(), ''):
print(line, end='')
这适用于Python 2和Python 3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.