little example endian bytes array python int bytearray

python - example - Convertir una matriz de bytes de tamaño variable en un entero/largo



python struct example (2)

La función docs.python.org/2/library/struct.html hace lo que necesita.

¿Cómo puedo convertir una matriz de bytes binarios de tamaño variable (big endian) en un entero / sin signo (sin signo)? Como ejemplo, ''/x11/x34'' , que representa 4404

En este momento, estoy usando

def bytes_to_int(bytes): return int(bytes.encode(''hex''), 16)

Que es pequeño y algo legible, pero probablemente no muy eficiente. ¿Hay alguna forma mejor (más obvia)?


Python tradicionalmente no tiene mucho uso para los "números en el diseño de big-endian C" que son demasiado grandes para C. (Si se trata de números de 2 bytes, 4 bytes u 8 bytes, struct.unpack es la respuesta.)

Pero hay suficiente gente que se int.from_bytes que no hubiera una forma obvia de hacer esto, por lo que Python 3.2 agregó un método int.from_bytes que hace exactamente lo que usted quiere:

int.from_bytes(b, byteorder=''big'', signed=False)

Desafortunadamente, si está utilizando una versión anterior de Python, no tiene esta. Entonces, ¿qué opciones tienes? (Además de lo obvio: actualización a 3.2, o, mejor, 3.4 ...)

Primero, ahí está tu código. Creo que binascii.hexlify es una mejor manera de deletrearlo que .encode(''hex'') , porque "codificar" siempre ha sido un poco extraño para un método en cadenas de bytes (en oposición a cadenas de Unicode), y de hecho ha sido desterrado en Python 3. Pero por lo demás, me parece bastante legible y obvio. Y debería ser bastante rápido; sí, tiene que crear una cadena intermedia, pero está haciendo todo el ciclo y la aritmética en C (al menos en CPython), que generalmente es un orden de magnitud o dos más rápido que en Python. A menos que su bytearray sea ​​tan grande que la asignación de la cadena sea costosa, no me preocuparía el rendimiento aquí.

Alternativamente, podrías hacerlo en un bucle. Pero eso será más detallado y, al menos en CPython, mucho más lento.

Podría intentar eliminar el bucle explícito de uno implícito, pero la función obvia para hacerlo es reduce , lo que se considera no pitónico por parte de la comunidad, y por supuesto requerirá llamar una función para cada byte.

Podría desenrollar el bucle o reduce struct.unpack_from en trozos de 8 bytes y struct.unpack_from en struct.unpack_from , o simplemente haciendo un gran struct.unpack(''Q''*len(b)//8 + ''B'' * len(b)%8) y repitiendo eso, pero eso lo hace mucho menos legible y probablemente no mucho más rápido.

Podría usar NumPy ... pero si va a ser más grande que 64 o quizás 128 bits, de todos modos va a terminar convirtiendo todo en objetos Python.

Entonces, creo que tu respuesta es la mejor opción.

Aquí hay algunos tiempos que lo comparan con la conversión manual más obvia:

import binascii import functools import numpy as np def hexint(b): return int(binascii.hexlify(b), 16) def loop1(b): def f(x, y): return (x<<8)|y return functools.reduce(f, b, 0) def loop2(b): x = 0 for c in b: x <<= 8 x |= c return x def numpily(b): n = np.array(list(b)) p = 1 << np.arange(len(b)-1, -1, -1, dtype=object) return np.sum(n * p)

In [226]: b = bytearray(range(256)) In [227]: %timeit hexint(b) 1000000 loops, best of 3: 1.8 µs per loop In [228]: %timeit loop1(b) 10000 loops, best of 3: 57.7 µs per loop In [229]: %timeit loop2(b) 10000 loops, best of 3: 46.4 µs per loop In [283]: %timeit numpily(b) 10000 loops, best of 3: 88.5 µs per loop

Para comparación en Python 3.4:

In [17]: %timeit hexint(b) 1000000 loops, best of 3: 1.69 µs per loop In [17]: %timeit int.from_bytes(b, byteorder=''big'', signed=False) 1000000 loops, best of 3: 1.42 µs per loop

Entonces, tu método sigue siendo bastante rápido ...