¿Cuál es la forma correcta de convertir bytes a una cadena hexadecimal en Python 3?

236

¿Cuál es la forma correcta de convertir bytes a una cadena hexadecimal en Python 3?

Veo reclamos de un bytes.hexmétodo, bytes.decodecódecs, y he probado otras posibles funciones de menor asombro sin resultado. ¡Solo quiero mis bytes como hexadecimales!

Matt Joiner
fuente
"en vano"? ¿Qué problemas o errores específicos tienes? Por favor, muestre el código y los errores.
S.Lott

Respuestas:

410

Desde Python 3.5 esto finalmente ya no es incómodo:

>>> b'\xde\xad\xbe\xef'.hex()
'deadbeef'

y reversa:

>>> bytes.fromhex('deadbeef')
b'\xde\xad\xbe\xef'

Funciona también con el bytearraytipo mutable .

Referencia: https://docs.python.org/3/library/stdtypes.html#bytes.hex

Felix Weis
fuente
55
bytes.fromhex()también está disponible en Python 3.0+ (no solo 3.5+). bytes.hex()solo está en Python 3.5+.
Phoenix
95

Usa el binasciimódulo:

>>> import binascii
>>> binascii.hexlify('foo'.encode('utf8'))
b'666f6f'
>>> binascii.unhexlify(_).decode('utf8')
'foo'

Ver esta respuesta: Python 3.1.1 cadena a hexadecimal

Mu Mind
fuente
8
Esto es bueno. Alucinante es que puedes convertir hexadecimal a bytes usando bytes.fromhex (hex_str), pero no puedes convertir bytes a hexadecimal usando bytes.tohex (): ¿cuál es la razón en esto?
nagylzs
1
Supongo que la relación entre bytes y hexadecimal no es una propiedad de ninguno de los dos (lo que no responde por qué fromhex está allí). Parece que no fue solo un descuido, sino algo sobre lo que se discutió: bugs.python.org/issue3532#msg70950 . P: ¿Le dolería tener el método tohex del objeto bytes para realizar esta tarea también? A: OMI, sí, lo haría. Complica el código y aleja el enfoque del enfoque adecuado para la conversión de datos (es decir, funciones, no métodos).
Mu Mind
3
¿Esto realmente responde la pregunta? No devuelve un hex strpero a bytes. Yo sé que el PO parece contento con la respuesta, pero no va a ser mejor para expandir esta respuesta para incluir .decode("ascii")también a convertirla en una "cadena"
RubenLaguna
3
Estaba pensando que muchas personas llegan a esta pregunta / respuesta buscando una forma de imprimir a bytes. Si print(b'666f6f')obtienes el ben la impresión. Si tú .decode("ascii")entonces no lo haces. Solo pensando en cómo aquellos que realmente tenían un bytes(binario verdadero con elementos> 128, no una cadena ascii) querían imprimirlo.
RubenLaguna
55
@nagylzs: hay un .hex()método en Python
3.5+
43

Python tiene códecs estándar de bytes a bytes que realizan transformaciones convenientes como imprimible entre comillas (encaja en 7 bits ascii), base64 (encaja en alfanuméricos), escape hexadecimal, compresión gzip y bz2. En Python 2, podrías hacer:

b'foo'.encode('hex')

En Python 3, str.encode/ bytes.decodeson estrictamente para conversiones bytes <-> str. En cambio, puede hacer esto, que funciona en Python 2 y Python 3 ( s / encode / decode / g para el inverso):

import codecs
codecs.getencoder('hex')(b'foo')[0]

Comenzando con Python 3.4, hay una opción menos incómoda:

codecs.encode(b'foo', 'hex')

Estos códecs misceláneos también son accesibles dentro de sus propios módulos (base64, zlib, bz2, uu, quopri, binascii); la API es menos consistente, pero para los códecs de compresión ofrece más control.

Gabriel
fuente
1
usando Python 3.3:LookupError: unknown encoding: hex
Janus Troelsen
@JanusTroelsen: prueba 'hex_codec' . O simplemente usar binascii.hexlify(b'foo')directamente
jfs
7
import codecs
codecs.getencoder('hex_codec')(b'foo')[0]

funciona en Python 3.3 (por lo tanto, "hex_codec" en lugar de "hex").

Richard Kiss
fuente
Quizás sea interesante, en Python 3.4 "hex" o "hex_codec" funciona bien.
Stephen Paulger
6

El método binascii.hexlify()se convertirá bytesen una bytesrepresentación de la cadena hexadecimal ascii. Eso significa que cada byte en la entrada se convertirá en dos caracteres ascii. Si quieres una verdadera strsalida, entonces puedes obtener .decode("ascii")el resultado.

Incluí un fragmento que lo ilustra.

import binascii

with open("addressbook.bin", "rb") as f: # or any binary file like '/bin/ls'
    in_bytes = f.read()
    print(in_bytes) # b'\n\x16\n\x04'
    hex_bytes = binascii.hexlify(in_bytes) 
    print(hex_bytes) # b'0a160a04' which is twice as long as in_bytes
    hex_str = hex_bytes.decode("ascii")
    print(hex_str) # 0a160a04

desde la cadena hexadecimal "0a160a04"a puede volver a la bytescon la binascii.unhexlify("0a160a04")que devuelveb'\n\x16\n\x04'

RubenLaguna
fuente
3

De acuerdo, la siguiente respuesta está un poco fuera de alcance si solo te importa Python 3, pero esta pregunta es el primer éxito de Google incluso si no especificas la versión de Python, así que aquí hay una manera que funciona tanto en Python 2 como en Python 3 .

También estoy interpretando que la pregunta es sobre la conversión de bytes al strtipo: es decir, bytes-y en Python 2 y Unicode-y en Python 3.

Dado eso, el mejor enfoque que conozco es:

import six

bytes_to_hex_str = lambda b: ' '.join('%02x' % i for i in six.iterbytes(b))

La siguiente afirmación será cierta para Python 2 o Python 3, suponiendo que no haya activado el unicode_literalsfuturo en Python 2:

assert bytes_to_hex_str(b'jkl') == '6a 6b 6c'

(O puede usar ''.join()para omitir el espacio entre los bytes, etc.)

Peter
fuente
3

se puede usar el especificador de %x02formato que formatea y genera un valor hexadecimal. Por ejemplo:

>>> foo = b"tC\xfc}\x05i\x8d\x86\x05\xa5\xb4\xd3]Vd\x9cZ\x92~'6"
>>> res = ""
>>> for b in foo:
...     res += "%02x" % b
... 
>>> print(res)
7443fc7d05698d8605a5b4d35d56649c5a927e2736
Arg0s
fuente
Según yo, es la mejor respuesta porque funciona con todas las versiones de Python y no necesita ninguna importación. Sin embargo, sería mejor mostrar cadenas hexa en mayúsculasres.upper()
Bruno L.
3

Nuevo en Python 3.8, puede pasar un argumento delimitador a la hexfunción, como en este ejemplo

>>> value = b'\xf0\xf1\xf2'
>>> value.hex('-')
'f0-f1-f2'
>>> value.hex('_', 2)
'f0_f1f2'
>>> b'UUDDLRLRAB'.hex(' ', -4)
'55554444 4c524c52 4142'

https://docs.python.org/3/library/stdtypes.html#bytes.hex

Peter Mitrano
fuente
0

Si desea convertir b '\ x61' a 97 o '0x61', puede intentar esto:

[python3.5]
>>>from struct import *
>>>temp=unpack('B',b'\x61')[0] ## convert bytes to unsigned int
97
>>>hex(temp) ##convert int to string which is hexadecimal expression
'0x61'

Referencia: https://docs.python.org/3.5/library/struct.html

hao li
fuente
De alguna manera me ayuda con esp32
Tejas Tank