Python 2到3转换:在子流程stdout中的行上迭代

fog*_*rit 3 python subprocess python-3.x

我有以下要与Python 3兼容的Python 2示例代码:

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='')
Run Code Online (Sandbox Code Playgroud)

这在Python 2中效果很好,但是在Python 3 p.stdout中不允许我指定编码,读取它会返回字节字符串,而不是Unicode,因此与的比较''将始终返回false并且iter不会停止。这个问题似乎意味着在Python 3.6中将有一种定义此编码的方法。

现在,我已将iter调用更改为在找到一个空字节字符串时停止它iter(p.stdout.readline, b''),它似乎在2和3中都有效。我的问题是:在2和3中这都安全吗?有没有更好的方法来确保兼容性?

注意:我没有使用,for line in p.stdout:因为我需要在生成每行时打印每行,并且根据此答案, p.stdout缓冲区太大。

Set*_*ton 7

您可以添加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='')
Run Code Online (Sandbox Code Playgroud)

将返回而不是bytesstr因此''在两种情况下都可以使用。

这是文档关于该选项必须说的:

如果Universal_newlines为False,则文件对象stdin,stdout和stderr将作为二进制流打开,并且不进行任何行尾转换。

如果Universal_newlines为True,则这些文件对象将使用locale.getpreferredencoding(False)返回的编码在通用换行模式下作为文本流打开。对于stdin,输入中的行尾字符'\ n'将转换为默认的行分隔符os.linesep。对于stdout和stderr,输出中的所有行尾都将转换为'\ n'。有关更多信息,请参见io.TextIOWrapper类的构造函数,当其构造函数的换行符为None时。

它没有明确指出bytesvs str差异,但是通过声明False返回二进制流并True返回文本流来暗示它。