为什么python2和python3中的print输出与同一个字符串不同?

lzu*_*tao 8 python unicode utf-8

在python2中:

$ python2 -c 'print "\x08\x04\x87\x18"' | hexdump -C
00000000  08 04 87 18 0a                                    |.....|
00000005
Run Code Online (Sandbox Code Playgroud)

在python3中:

$ python3 -c 'print("\x08\x04\x87\x18")' | hexdump -C
00000000  08 04 c2 87 18 0a                                 |......|
00000006
Run Code Online (Sandbox Code Playgroud)

为什么"\xc2"这里有字节?

编辑:

我认为当字符串具有非ascii字符时,python3会将字节附加"\xc2"到字符串.(正如@Ashraful Islam所说)

那我怎么能在python3中避免这种情况呢?

Tom*_*ych 13

请考虑以下代码段:

import sys
for i in range(128, 256):
    sys.stdout.write(chr(i))
Run Code Online (Sandbox Code Playgroud)

使用Python 2运行它并查看结果hexdump -C:

00000000  80 81 82 83 84 85 86 87  88 89 8a 8b 8c 8d 8e 8f  |................|
Run Code Online (Sandbox Code Playgroud)

等等.没有惊喜; 从128个字节0x800xff.

使用Python 3执行相同的操作:

00000000  c2 80 c2 81 c2 82 c2 83  c2 84 c2 85 c2 86 c2 87  |................|
...
00000070  c2 b8 c2 b9 c2 ba c2 bb  c2 bc c2 bd c2 be c2 bf  |................|
00000080  c3 80 c3 81 c3 82 c3 83  c3 84 c3 85 c3 86 c3 87  |................|
...
000000f0  c3 b8 c3 b9 c3 ba c3 bb  c3 bc c3 bd c3 be c3 bf  |................|
Run Code Online (Sandbox Code Playgroud)

总结一下:

  • 一切从0x800xbf已经0xc2预先考虑.
  • 从一切0xc00xff了第6位设定为零,并且已经0xc3预先考虑.

那么,这里发生了什么?

在Python 2中,字符串是ASCII,不进行转换.告诉它写出0-127 ASCII范围之外的东西,它说"okey-doke!"并且只写那些字节.简单.

在Python 3中,字符串是Unicode.写入非ASCII字符时,必须以某种方式对它们进行编码.默认编码为UTF-8.

那么,这些值如何用UTF-8编码?

从代码点0x800x7ff编码如下:

110vvvvv 10vvvvvv
Run Code Online (Sandbox Code Playgroud)

其中11个v字符是代码点的位.

从而:

0x80                 hex
1000 0000            8-bit binary
000 1000 0000        11-bit binary
00010 000000         divide into vvvvv vvvvvv
11000010 10000000    resulting UTF-8 octets in binary
0xc2 0x80            resulting UTF-8 octets in hex

0xc0                 hex
1100 0000            8-bit binary
000 1100 0000        11-bit binary
00011 000000         divide into vvvvv vvvvvv
11000011 10000000    resulting UTF-8 octets in binary
0xc3 0x80            resulting UTF-8 octets in hex
Run Code Online (Sandbox Code Playgroud)

所以这就是你c2之前得到的原因87.

如何在Python 3中避免这一切?使用bytes类型.


Mar*_*nen 5

Python 2 的默认字符串类型是字节字符串。写入字节字符串的同时写入"abc"Unicode 字符串u"abc"

Python 3 的默认字符串类型是 Unicode 字符串。字节字符串的写入方式与b"abc"Unicode 字符串的写入方式相同"abc"u"abc"仍然有效)。由于有数百万个 Unicode 字符,将它们打印为字节需要一种编码(在您的情况下为UTF-8),每个代码点需要多个字节。

首先在 Python 3 中使用字节字符串来获取与 Python 2 相同的类型。然后,因为 Python 3print需要 Unicode 字符串,所以使用sys.stdout.buffer.write写入原始 stdout 接口,该接口需要字节字符串。

python3 -c 'import sys; sys.stdout.buffer.write(b"\x08\x04\x87\x18")'
Run Code Online (Sandbox Code Playgroud)

请注意,如果写入文件,则存在类似问题。对于无编码转换,以二进制模式打开文件'wb'并写入字节字符串。