¿Cómo puedo convertir una cadena de bytes en un int en python?
Diga así: 'y\xcc\xa6\xbb'
Se me ocurrió una forma inteligente / estúpida de hacerlo:
sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))
Sé que tiene que haber algo incorporado o en la biblioteca estándar que haga esto de manera más simple ...
Esto es diferente de convertir una cadena de dígitos hexadecimales para los que puede usar int (xxx, 16), pero en su lugar quiero convertir una cadena de valores de bytes reales.
ACTUALIZAR:
Me gusta un poco la respuesta de James porque no requiere importar otro módulo, pero el método de Greg es más 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
Mi método hacky:
>>> Timer("sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))").timeit()
2.8819329738616943
ACTUALIZACIÓN ADICIONAL:
Alguien preguntó en los comentarios cuál es el problema con la importación de otro módulo. Bueno, importar un módulo no es necesariamente barato, eche un vistazo:
>>> Timer("""import struct\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""").timeit()
0.98822188377380371
Incluyendo el costo de importar el módulo niega casi todas las ventajas que tiene este método. Creo que esto solo incluirá el gasto de importarlo una vez para toda la prueba de referencia; mira lo que sucede cuando lo obligo a recargar cada vez:
>>> Timer("""reload(struct)\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""", 'import struct').timeit()
68.474128007888794
No hace falta decir que si realiza muchas ejecuciones de este método por importación, esto proporcionalmente será un problema menor. También es probable que sea un costo de E / S en lugar de una CPU, por lo que puede depender de la capacidad y las características de carga de la máquina en particular.
int.from_bytes
) se superóstruct.unpack
en mi computadora. Junto a ser más legible imo.Respuestas:
También puede usar el módulo de estructura para hacer esto:
fuente
En Python 3.2 y posterior, use
o
de acuerdo con el endianness de su cadena de bytes.
Esto también funciona para enteros de bytes de longitud arbitraria y para enteros con signo de complemento a dos especificando
signed=True
. Ver los documentos parafrom_bytes
.fuente
os.urandom(4)
bytes ** 1.4 µs ** (struct) vs ** 2.3 µs ** (int.from_bytes) en mi CPU. python 3.5.2Como dijo Greg, puede usar struct si está tratando con valores binarios, pero si solo tiene un "número hexadecimal" pero en formato de bytes, es posible que desee convertirlo como:
... esto es lo mismo que:
... excepto que funcionará para cualquier número de bytes.
fuente
int(''.join(reversed(s)).encode('hex'), 16)
Utilizo la siguiente función para convertir datos entre int, hexadecimal y bytes.
Fuente: http://opentechnotes.blogspot.com.au/2014/04/convert-values-to-from-integer-hex.html
fuente
Advertencia: lo anterior es muy específico de la plataforma. Tanto el especificador "I" como el endianness de la conversión string-> int dependen de su implementación particular de Python. Pero si desea convertir muchos enteros / cadenas a la vez, entonces el módulo de matriz lo hace rápidamente.
fuente
En Python 2.x, puede usar los especificadores de formato
<B
para bytes sin firmar y<b
para bytes construct.unpack
/struct.pack
.P.ej:
Let
x
='\xff\x10\x11'
Y:
Eso
*
es requerido!Ver https://docs.python.org/2/library/struct.html#format-characters para obtener una lista de los especificadores de formato.
fuente
Prueba 1: inversa:
Prueba 2: Número de bytes> 8:
Prueba 3: Incremento en uno:
Prueba 4: agregue un byte, diga 'A':
Prueba 5: dividir entre 256:
El resultado es igual al resultado de la Prueba 4, como se esperaba.
fuente
Estaba luchando por encontrar una solución para secuencias arbitrarias de bytes de longitud que funcionaran con Python 2.x. Finalmente escribí este, es un poco hacky porque realiza una conversión de cadena, pero funciona.
Función para Python 2.x, longitud arbitraria
Esta función tiene dos requisitos:
La entrada
data
debe ser abytearray
. Puede llamar a la función de esta manera:Los datos deben ser big-endian. En caso de que tenga un valor little-endian, primero debe revertirlo:
Por supuesto, esto debe usarse solo si se necesita una longitud arbitraria. De lo contrario, quédese con formas más estándar (por ejemplo
struct
).fuente
int.from_bytes es la mejor solución si está en la versión> = 3.2. La solución "struct.unpack" requiere una cadena para que no se aplique a las matrices de bytes. Aquí hay otra solución:
hex (bytes2int ([0x87, 0x65, 0x43, 0x21])) devuelve '0x87654321'.
Maneja endianness grande y pequeño y es fácilmente modificable para 8 bytes
fuente
Como se mencionó anteriormente, usar la
unpack
función de struct es una buena manera. Si desea implementar su propia función, existe otra solución:fuente
En python 3 puede convertir fácilmente una cadena de bytes en una lista de enteros (0..255) por
fuente
Un método bastante rápido que utiliza array.array que he estado usando durante algún tiempo:
variables predefinidas:
int: (leer)
de int: (escribir)
Sin embargo, es posible que estos sean más rápidos.
EDITAR:
para algunos números, aquí hay una prueba de rendimiento (Anaconda 2.3.0) que muestra promedios estables en lectura en comparación con
reduce()
:Esta es una prueba de rendimiento sin procesar, por lo que se omite el cambio de potencia endian.
La
shift
función mostrada aplica la misma operación de cambio de orden que el bucle for, yarr
es igualarray.array('B',[0,0,255,0])
que tiene el rendimiento iterativo más rápido al ladodict
.Probablemente también debería notar que la eficiencia se mide por la precisión del tiempo promedio.
fuente