Qual é a maneira correta de converter bytes em uma string hexadecimal no Python 3?

236

Qual é a maneira correta de converter bytes em uma string hexadecimal no Python 3?

Vejo reivindicações de um bytes.hexmétodo, bytes.decodecodecs e tentei outras funções possíveis de menor espanto, sem sucesso. Eu só quero meus bytes como hexadecimal!

Matt Joiner
fonte
"sem sucesso"? Quais problemas ou erros específicos você está recebendo? Por favor, mostre o código e os erros.
S.Lott 8/07

Respostas:

410

Desde o Python 3.5, isso finalmente não é mais complicado:

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

e inverter:

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

funciona também com o bytearraytipo mutável .

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

Felix Weis
fonte
5
bytes.fromhex()também está disponível no Python 3.0+ (não apenas 3.5+). bytes.hex()está disponível apenas no Python 3.5+.
Phoenix
95

Use o binasciimódulo:

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

Veja esta resposta: Python 3.1.1 string to hex

Mu Mind
fonte
8
Isso é bom. Impressionante é que você pode converter hexadecimal em bytes usando bytes.fromhex (hex_str), mas não pode converter bytes em hexadecimal usando bytes.tohex () - qual é o racional nisso?
Nagylzs
1
Eu acho que a relação entre bytes e hexadecimal não é propriedade de nenhum dos dois (o que não responde por que o fromhex existe). Parece que não foi apenas um descuido, mas algo que foi discutido: bugs.python.org/issue3532#msg70950 . P: Doeria ter o método tohex do objeto bytes para executar esta tarefa também? A: IMO, sim, seria. Isso complica o código e afasta o foco da abordagem adequada à conversão de dados (ou seja, funções - não métodos).
quer
3
Isso realmente responde à pergunta? Não retorna um hex, strmas a bytes. Eu sei que o OP parece feliz com a resposta, mas não vai ser melhor para expandir esta resposta para incluir .decode("ascii")também para convertê-lo em um "string"
RubenLaguna
3
Eu estava pensando que muitas pessoas pousam nessa pergunta / resposta procurando uma maneira de imprimir a bytes. Se você print(b'666f6f')receber ba impressão. Se você, .decode("ascii")então você não. Apenas pensando em como aqueles que realmente tinham um bytes(binário verdadeiro com itens> 128, não uma string ascii) queriam imprimi-lo.
precisa saber é o seguinte
5
@ nagylzs: existe .hex()método no Python 3.5+
jfs
43

O Python possui codecs padrão de bytes em bytes que executam transformações convenientes como quoted-printable (cabe em 7bits ascii), base64 (cabe em alfanuméricos), escape hexadecimal, compressão gzip e bz2. No Python 2, você pode fazer:

b'foo'.encode('hex')

No Python 3, str.encode/ bytes.decodesão estritamente para conversões de bytes <-> str. Em vez disso, você pode fazer isso, que funciona no Python 2 e Python 3 ( s / encode / decode / g para o inverso):

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

Começando com o Python 3.4, existe uma opção menos complicada:

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

Esses codecs variados também são acessíveis dentro de seus próprios módulos (base64, zlib, bz2, uu, quopri, binascii); a API é menos consistente, mas para codecs de compactação oferece mais controle.

Gabriel
fonte
1
usando python 3.3: #LookupError: unknown encoding: hex
Janus Troelsen
@JanusTroelsen: tente 'hex_codec' . Ou simplesmente usar binascii.hexlify(b'foo')diretamente
JFS
7
import codecs
codecs.getencoder('hex_codec')(b'foo')[0]

funciona em Python 3.3 (então "hex_codec" em vez de "hex").

Richard Kiss
fonte
Talvez, curiosamente, no Python 3.4, "hex" ou "hex_codec" funcionem bem.
Stephen Paulger
6

O método binascii.hexlify()será convertido bytesem um bytesrepresentando a cadeia hexadecimal ascii. Isso significa que cada byte na entrada será convertido em dois caracteres ascii. Se você quer uma strsaída verdadeira , pode obter .decode("ascii")o resultado.

Eu incluí um trecho que ilustra isso.

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

da cadeia hexadecimal "0a160a04"para pode voltar para o bytescom o binascii.unhexlify("0a160a04")qual devolveb'\n\x16\n\x04'

RubenLaguna
fonte
3

OK, a resposta a seguir é um pouco além do escopo se você se importa apenas com o Python 3, mas esta pergunta é a primeira ocorrência do Google, mesmo que você não especifique a versão do Python, então aqui está uma maneira de funcionar tanto no Python 2 quanto no Python 3 .

Também estou interpretando a questão de converter bytes para o strtipo: ou seja, bytes-y no Python 2 e Unicode-y no Python 3.

Dado isso, a melhor abordagem que conheço é:

import six

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

A afirmação a seguir será verdadeira para Python 2 ou Python 3, supondo que você não tenha ativado o unicode_literalsfuturo no Python 2:

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

(Ou você pode usar ''.join()para omitir o espaço entre os bytes etc.)

Peter
fonte
3

pode ser usado o especificador de %x02formato que formata e gera um valor hexadecimal. Por exemplo:

>>> 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
fonte
De acordo com mim, é a melhor resposta, pois funciona com todas as versões do Python e não precisa de importação. No entanto, é melhor exibir seqüências hexa em maiúsculasres.upper()
Bruno L.
3

Novo no python 3.8, você pode passar um argumento delimitador para a hexfunção, como neste exemplo

>>> 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
fonte
0

Se você deseja converter b '\ x61' em 97 ou '0x61', tente o seguinte:

[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'

Referência: https://docs.python.org/3.5/library/struct.html

hao li
fonte
De alguma forma me ajuda com esp32
Tejas Tank