Python 2 到 3 转换:遍历子进程标准输出中的行

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 不允许我指定编码并且读取它将 return 字节字符串,而不是Unicode,所以与 '' 的比较总是 return false 而 iter 不会停止。 This issue 似乎暗示在 Python 3.6 中将有一种方法来定义这种编码。

目前,我已将 iter 调用更改为在发现空字节字符串 iter(p.stdout.readline, b'') 时停止,这似乎在 2 和 3 中有效。我的问题是:这在2 和 3?有没有更好的办法保证兼容性?

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

如果是bytes对象,可以使用p.communicate()然后解码:

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

您可以添加 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='')

将返回 str 而不是 bytes,因此 '' 在两种情况下都有效。

以下是文档对选项的说明:

If universal_newlines is False the file objects stdin, stdout and stderr will be opened as binary streams, and no line ending conversion is done.

If universal_newlines is True, these file objects will be opened as text streams in universal newlines mode using the encoding returned by locale.getpreferredencoding(False). For stdin, line ending characters '\n' in the input will be converted to the default line separator os.linesep. For stdout and stderr, all line endings in the output will be converted to '\n'. For more information see the documentation of the io.TextIOWrapper class when the newline argument to its constructor is None.

没有明确指出 bytesstr 的区别,但通过声明 False returns 二进制流和 True returns 一个文本流。