Como posso converter uma sequência de bytes em um int em python?
Diga assim: 'y\xcc\xa6\xbb'
Eu vim com uma maneira inteligente / estúpida de fazer isso:
sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))
Eu sei que tem que haver algo embutido ou na biblioteca padrão que faça isso de forma mais simples ...
Isso é diferente de converter uma sequência de dígitos hexadecimais para a qual você pode usar int (xxx, 16), mas, em vez disso, desejo converter uma sequência de valores reais de bytes.
ATUALIZAR:
Eu meio que gosto da resposta de James um pouco melhor porque não requer a importação de outro módulo, mas o método de Greg é mais rápido:
>>> from timeit import Timer
>>> Timer('struct.unpack("<L", "y\xcc\xa6\xbb")[0]', 'import struct').timeit()
0.36242198944091797
>>> Timer("int('y\xcc\xa6\xbb'.encode('hex'), 16)").timeit()
1.1432669162750244
Meu método hacky:
>>> Timer("sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))").timeit()
2.8819329738616943
ATUALIZAÇÃO ATUALIZADA:
Alguém perguntou nos comentários qual é o problema com a importação de outro módulo. Bem, importar um módulo não é necessariamente barato, dê uma olhada:
>>> Timer("""import struct\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""").timeit()
0.98822188377380371
A inclusão do custo de importação do módulo nega quase toda a vantagem que esse método possui. Acredito que isso incluirá apenas as despesas de importação uma vez durante toda a execução do benchmark; veja o que acontece quando eu o forço a recarregar toda vez:
>>> Timer("""reload(struct)\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""", 'import struct').timeit()
68.474128007888794
Desnecessário dizer que, se você estiver executando muitas execuções desse método por importação, isso se tornará proporcionalmente menos problemático. Provavelmente, também é um custo de E / S em vez de CPU, por isso pode depender das características de capacidade e carga de uma máquina específica.
int.from_bytes
) foi superadastruct.unpack
no meu computador. Além de ser mais legível, imo.Respostas:
Você também pode usar o módulo struct para fazer isso:
fonte
No Python 3.2 e posterior, use
ou
de acordo com o endianness da sua string de bytes.
Isso também funciona para bytes inteiros de comprimento arbitrário e para números inteiros assinados com complemento de dois, especificando
signed=True
. Veja os documentos parafrom_bytes
.fonte
os.urandom(4)
bytes ** 1,4 µs ** (struct) vs ** 2,3 µs ** (int.from_bytes) no meu processador. python 3.5.2Como Greg disse, você pode usar struct se estiver lidando com valores binários, mas se você tiver apenas um "número hexadecimal", mas no formato de byte, poderá convertê-lo como:
... é o mesmo que:
... exceto que funcionará para qualquer número de bytes.
fonte
int(''.join(reversed(s)).encode('hex'), 16)
Eu uso a seguinte função para converter dados entre int, hex e bytes.
Fonte: http://opentechnotes.blogspot.com.au/2014/04/convert-values-to-from-integer-hex.html
fonte
Aviso: o acima é fortemente específico da plataforma. Tanto o especificador "I" quanto a resistência da conversão string-> int dependem da sua implementação específica do Python. Mas se você deseja converter muitos números inteiros / seqüências de uma vez, o módulo array faz isso rapidamente.
fonte
No Python 2.x, você pode usar os especificadores de formato
<B
para bytes não assinados e<b
para bytes assinados comstruct.unpack
/struct.pack
.Por exemplo:
Let
x
='\xff\x10\x11'
E:
Isso
*
é necessário!Vejo https://docs.python.org/2/library/struct.html#format-characters para obter uma lista dos especificadores de formato.
fonte
Teste 1: inverso:
Teste 2: Número de bytes> 8:
Teste 3: incremento de um:
Teste 4: acrescente um byte, diga 'A':
Teste 5: Divida por 256:
Resultado é igual ao resultado do Teste 4, conforme o esperado.
fonte
Eu estava lutando para encontrar uma solução para seqüências arbitrárias de bytes de comprimento que funcionassem no Python 2.x. Finalmente eu escrevi este, é um pouco hacky porque realiza uma conversão de string, mas funciona.
Função para Python 2.x, tamanho arbitrário
Esta função possui dois requisitos:
A entrada
data
precisa ser abytearray
. Você pode chamar a função assim:Os dados precisam ser big-endian. Caso você tenha um valor little-endian, você deve revertê-lo primeiro:
Obviamente, isso deve ser usado apenas se for necessário um tamanho arbitrário. Caso contrário, atenha-se a formas mais padrão (por exemplo
struct
).fonte
int.from_bytes é a melhor solução se você estiver na versão> = 3.2. A solução "struct.unpack" requer uma string para que não se aplique a matrizes de bytes. Aqui está outra solução:
hex (bytes2int ([0x87, 0x65, 0x43, 0x21])) retorna '0x87654321'.
Ele lida com endianness grande e pequeno e é facilmente modificável por 8 bytes
fonte
Como mencionado acima, usar a
unpack
função de struct é uma boa maneira. Se você deseja implementar sua própria função, existe outra solução:fonte
No python 3, você pode converter facilmente uma sequência de bytes em uma lista de números inteiros (0..255)
fonte
Um método decentemente rápido que utiliza array.array que venho usando há algum tempo:
variáveis predefinidas:
para int: (leia)
from int: (gravação)
É possível que eles possam ser mais rápidos.
EDIT:
Para alguns números, aqui está um teste de desempenho (Anaconda 2.3.0) mostrando médias estáveis na leitura em comparação com
reduce()
:Este é um teste de desempenho bruto, então o endian pow-flip é deixado de fora.
A
shift
função mostrada aplica a mesma operação shift-oring que o looparr
for earray.array('B',[0,0,255,0])
apresenta o desempenho iterativo mais rápido ao ladodict
.Provavelmente também devo observar que a eficiência é medida pela precisão do tempo médio.
fonte