Python 3 TypeError:必须是 str,而不是 sys.stdout.write() 的字节 [英] Python 3 TypeError: must be str, not bytes with sys.stdout.write()

查看:76
本文介绍了Python 3 TypeError:必须是 str,而不是 sys.stdout.write() 的字节的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<块引用>

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

p = subprocess.Popen(["demo.exe"],stdout = subprocess.PIPE, stderr= subprocess.PIPE)# 轮询新输出的过程直到完成为真:nextline = p.stdout.readline()if nextline == '' and p.poll() != None:休息sys.stdout.write(下一行)sys.stdout.flush()输出 = p.communicate()[0]exitCode = p.returncode

我使用的是 python 3.3.2

解决方案

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

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

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

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

此更改与 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 更改为字节.这是因为 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''错误的

另见 Python 3ChangeLogPEP 358PEP 3112.

<小时>

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

2 是的,你可以使用函数注解,但它是一个比较新的功能,很少使用.

I was looking for a way to run an external process from python script and print its stdout messages during the execution.
The code below works, but prints no stdout output during runtime. When it exits I am getting the following error:

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

I am using python 3.3.2

解决方案

Python 3 handles strings a bit different. Originally there was just one type for strings: str. When unicode gained traction in the '90s the new unicode type was added to handle Unicode without breaking pre-existing code1. This is effectively the same as str but with multibyte support.

In Python 3 there are two different types:

  • The bytes type. This is just a sequence of bytes, Python doesn't know anything about how to interpret this as characters.
  • The str type. This is also a sequence of bytes, but Python knows how to interpret those bytes as characters.
  • The separate unicode type was dropped. str now supports unicode.

In Python 2 implicitly assuming an encoding could cause a lot of problems; you could end up using the wrong encoding, or the data may not have an encoding at all (e.g. it’s a PNG image).
Explicitly telling Python which encoding to use (or explicitly telling it to guess) is often a lot better and much more in line with the "Python philosophy" of "explicit is better than implicit".

This change is incompatible with Python 2 as many return values have changed, leading to subtle problems like this one; it's probably the main reason why Python 3 adoption has been so slow. Since Python doesn't have static typing2 it's impossible to change this automatically with a script (such as the bundled 2to3).

  • You can convert str to bytes with bytes('h€llo', 'utf-8'); this should produce b'H\xe2\x82\xacllo'. Note how one character was converted to three bytes.
  • You can convert bytes to str with b'H\xe2\x82\xacllo'.decode('utf-8').

Of course, UTF-8 may not be the correct character set in your case, so be sure to use the correct one.

In your specific piece of code, nextline is of type bytes, not str, reading stdout and stdin from subprocess changed in Python 3 from str to bytes. This is because Python can't be sure which encoding this uses. It probably uses the same as sys.stdin.encoding (the encoding of your system), but it can't be sure.

You need to replace:

sys.stdout.write(nextline)

with:

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

or maybe:

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

You will also need to modify if nextline == '' to if nextline == b'' since:

>>> '' == b''
False

Also see the Python 3 ChangeLog, PEP 358, and PEP 3112.


1 There are some neat tricks you can do with ASCII that you can't do with multibyte character sets; the most famous example is the "xor with space to switch case" (e.g. chr(ord('a') ^ ord(' ')) == 'A') and "set 6th bit to make a control character" (e.g. ord('\t') + ord('@') == ord('I')). ASCII was designed in a time when manipulating individual bits was an operation with a non-negligible performance impact.

2 Yes, you can use function annotations, but it's a comparatively new feature and little used.

这篇关于Python 3 TypeError:必须是 str,而不是 sys.stdout.write() 的字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆