Python 3 TypeError: must be str, not bytes with sys.stdout.write()

Posted

技术标签:

【中文标题】Python 3 TypeError: must be str, not bytes with sys.stdout.write()【英文标题】: 【发布时间】:2014-03-08 12:02:49 【问题描述】:

我正在寻找一种从 python 脚本运行外部进程并在执行期间打印其标准输出消息的方法。 下面的代码有效,但在运行时不打印标准输出。当它退出时,我收到以下错误:

sys.stdout.write(nextline) TypeError:must be str,not bytes

p = subprocess.Popen(["demo.exe"],stdout = subprocess.PIPE, stderr= subprocess.PIPE)    
# Poll process for new output until finished
while True:
    nextline = p.stdout.readline()
    if nextline == '' and p.poll() != None:
        break
    sys.stdout.write(nextline)
    sys.stdout.flush()

output = p.communicate()[0]
exitCode = p.returncode

我正在使用 python 3.3.2

【问题讨论】:

builtins.TypeError: must be str, not bytes的可能重复 【参考方案1】:

Python 3 处理字符串有点不同。最初只有一种类型 字符串:str。当 unicode 在 90 年代获得关注时,新的 unicode 类型 已添加以处理 Unicode,而不会破坏预先存在的代码1。这是 实际上与str 相同,但支持多字节。

在 Python 3 中有两种不同的类型:

bytes 类型。这只是一个字节序列,Python不知道 关于如何将其解释为字符的任何信息。 str 类型。这也是一个字节序列,但是 Python 知道如何 将这些字节解释为字符。 单独的unicode 类型已删除。 str 现在支持 unicode。

在 Python 2 中,隐式假设编码可能会导致很多问题;你 最终可能会使用错误的编码,或者数据可能没有编码 全部(例如,它是 PNG 图像)。 明确告诉 Python 使用哪种编码(或明确告诉它 猜测)通常更好,更符合“Python哲学” 的“explicit is better than implicit”。

此更改与 Python 2 不兼容,因为许多返回值已更改, 导致像这样的微妙问题;这可能是主要原因 Python 3 的采用非常缓慢。由于 Python 没有静态类型2 不可能使用脚本自动更改它(例如捆绑的 2to3)。

您可以使用bytes('h€llo', 'utf-8')str 转换为bytes;这应该 产生b'H\xe2\x82\xacllo'。请注意如何将一个字符转换为三个 字节。 您可以使用b'H\xe2\x82\xacllo'.decode('utf-8')bytes 转换为str

当然,在您的情况下,UTF-8 可能不是正确的字符集,所以请确保 使用正确的。

在您的特定代码中,nextline 的类型为 bytes,而不是 str, 从 subprocess 读取 stdoutstdin 在 Python 3 中从 str 更改为 bytes。这是因为 Python 无法确定它使用的是哪种编码。它 可能使用与sys.stdin.encoding(您系统的编码)相同, 但不能确定。

你需要更换:

sys.stdout.write(nextline)

与:

sys.stdout.write(nextline.decode('utf-8'))

或者也许:

sys.stdout.write(nextline.decode(sys.stdout.encoding))

您还需要将if nextline == '' 修改为if nextline == b'',因为:

>>> '' == b''
False

另请参阅Python 3 ChangeLog、PEP 358 和 PEP 3112。


1 你可以用 ASCII 做一些巧妙的技巧,而用多字节字符集却做不到;最著名的例子是“xor with space to switch case”(例如chr(ord('a') ^ ord(' ')) == 'A')和“设置第6位以制作控制字符”(例如ord('\t') + ord('@') == ord('I'))。 ASCII 是在操作单个位是一项对性能影响不可忽视的操作时设计的。

2是的,你可以使用函数注解,但它是一个比较新的特性,很少使用。

【讨论】:

+1 提示!顺便说一句,我看到我只在程序结束时才获得标准输出。你能告诉我为什么它不能实时打印吗? 在不知道 demo.exe 输出什么以及 究竟 您想要什么的情况下,很难回答您的问题,因为不清楚问题是什么 :-) 请注意,readline() 读取 line,也就是说,它会一直读取直到遇到换行符,我相信在 Windows 上,它是 \r\n 而不是 \n 我要做的是在python中运行时打印demo.exe stdout消息。目前python仅在子进程终止时打印demo.exe stdout @MichaelIV 不知道为什么你没有任何输出。我测试了它,它对我有用。我还在 Windows 上对其进行了测试以确定。确保demo.exe 输出\r\n 行尾,并且demo.exe 也在刷新标准输出。【参考方案2】:

如果您从子进程中获得的字节是使用sys.stdout.encoding 编码的(或兼容的编码,例如从输出 ASCII 的工具中读取并且您的标准输出使用 UTF-8),则接受的答案将正常工作,但正确的方法将任意字节写入标准输出是:

sys.stdout.buffer.write(some_bytes_object)

这只会按原样输出字节,而不会尝试将它们视为 text-in-some-encoding。

【讨论】:

作为迁移的一部分,我会接受这个答案作为正确答案。例如,我无法更改 csv 模块写入数据的方式。所以在我看来,最好的方法就是将数据按原样传递给标准输出。感谢这篇文章! 谢谢!这就是我一直在寻找的:D

以上是关于Python 3 TypeError: must be str, not bytes with sys.stdout.write()的主要内容,如果未能解决你的问题,请参考以下文章

使用 pickle.dump - TypeError: must be str, not bytes

python TypeError: must be str, not bytes错误

Python. 报错: TypeError: issubclass() arg 1 must be a class

Python错误TypeError: write() argument must be str, not bytes

python报错 TypeError: string indices must be integers

使用 python 运行 bash 脚本 - TypeError: bufsize must be an integer