繁体   English   中英

Python 2到3转换:迭代子进程stdout中的行

[英]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时。

它没有明确地提到bytesstr区别,但是通过声明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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM