¿Por qué la salida de impresión en python2 y python3 es diferente con la misma cadena?

En python2:

$ python2 -c 'print "\x08\x04\x87\x18"' | hexdump -C 00000000 08 04 87 18 0a |.....| 00000005 

En python3:

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

¿Por qué tiene el byte "\xc2" aquí?

Editar :

Creo que cuando la cadena tiene un carácter que no es ASCII, Python3 agregará el byte "\xc2" a la cadena. (como dijo @Ashraful Islam)

Entonces, ¿cómo puedo evitar esto en python3?

Considere el siguiente fragmento de código:

 import sys for i in range(128, 256): sys.stdout.write(chr(i)) 

Ejecute esto con Python 2 y mire el resultado con hexdump -C :

 00000000 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................| 

Etcétera. No hay sorpresas; 128 bytes de 0x80 a 0xff .

Haz lo mismo con 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 |................| 

Para resumir:

  • Todo, desde 0x80 hasta 0xbf tiene 0xc2 .
  • Todo, desde 0xc0 hasta 0xff tiene el bit 6 establecido en cero y tiene 0xc3 .

Entonces, ¿qué está pasando aquí?

En Python 2, las cadenas son ASCII y no se realiza ninguna conversión. Dígale que escriba algo fuera del rango 0-127 ASCII, dice “¡okey-doke!” Y simplemente escribe esos bytes. Sencillo.

En Python 3, las cadenas son Unicode . Cuando se escriben caracteres que no son ASCII, deben codificarse de alguna manera. La encoding predeterminada es UTF-8.

Entonces, ¿cómo se codifican estos valores en UTF-8?

Los puntos de código de 0x80 a 0x7ff se codifican de la siguiente manera:

 110vvvvv 10vvvvvv 

Donde los caracteres de 11 v son los bits del punto de código.

Así:

 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 

Entonces es por eso que c2 un c2 antes del 87 .

¿Cómo evitar todo esto en Python 3? Utilice el tipo de bytes .

El tipo de cadena predeterminado de Python 2 es cadenas de bytes. Las cadenas de bytes se escriben "abc" mientras que las cadenas de Unicode se escriben u"abc" .

El tipo de cadena predeterminado de Python 3 es las cadenas Unicode. Las cadenas de bytes se escriben como b"abc" mientras que las cadenas de Unicode se escriben "abc" ( u"abc" también funciona). ya que hay millones de caracteres Unicode, imprimirlos como bytes requiere una encoding ( UTF-8 en su caso) que requiere múltiples bytes por punto de código.

Primero use una cadena de bytes en Python 3 para obtener el mismo tipo de Python 2. Luego, dado que la print Python 3 espera cadenas Unicode, use sys.stdout.buffer.write para escribir en la interfaz stdout sin formato, que espera cadenas de bytes.

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

Tenga en cuenta que si escribe en un archivo, hay problemas similares. Para la traducción sin encoding, abra los archivos en modo binario 'wb' y escriba cadenas de bytes.