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
读取 stdout
和 stdin
在 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