2008-12-22 25 views
6

Estoy intentando hablar con un dispositivo usando python. Me han dado una tupla de bytes que contiene la información de almacenamiento. ¿Cómo puedo convertir los datos en los valores correctos:Cómo convierto una parte de una tupla de python (matriz de bytes) en un número entero

respuesta = (0, 0, 117, 143, 6)

Los primeros 4 valores son un int de 32 bits decirme cuántos bytes se han utilizado y el último valor es el porcentaje utilizado.

Puedo acceder a la tupla como respuesta [0] pero no puedo ver cómo puedo obtener los primeros 4 valores en la int que requiero.

Respuesta

11

Ver Convert Bytes to Floating Point Numbers in Python

Es posible que desee utilizar el módulo de estructura, por ejemplo,

import struct 

response = (0, 0, 117, 143, 6) 
struct.unpack(">I", ''.join([chr(x) for x in response[:-1]])) 

Asumiendo un unsigned int. Puede haber una forma mejor de hacer la conversión para descomprimir, una lista de comprensión con join fue solo lo primero que se me ocurrió.

EDIT: Vea también el comentario de ΤΖΩΤΖΙΟΥ sobre esta respuesta con respecto al endianness también.

EDIT # 2: Si no te molesta usar el módulo de matriz también, aquí hay un método alternativo que evita la necesidad de una lista de comprensión. Gracias a @JimB para señalar que unpack también puede operar en arreglos.

import struct 
from array import array 

response = (0, 0, 117, 143, 6) 
bytes = array('B', response[:-1]) 
struct.unpack('>I', bytes) 
+1

Sugeriría que el formato del paquete sea "> I", es decir, big endian; 0x0000758f (30095₁₀) para un recuento aleatorio de bytes parece más probable que 0x8f750000 (2406809600₁₀) – tzot

13

haría,

num = (respuesta [0] < < 24) + (respuesta [1] < < 16) + (respuesta [2] < < 8) + respuesta [3]

¿Cumple con sus necesidades?

ayuda

+2

al leer las respuestas anteriores con módulos de importación, utilizando bucles y comprensiones para algo tan trivial como esto, realmente empecé a rascarme la cabeza ... esta respuesta es en realidad cómo se hace (y se debe hacer) en cualquier lugar, y nada superará esto en términos de velocidad y simplicidad ... – Tom

+0

Una manera fácil de hacerlo – user2578666

4

bien, tú no especifica el endinanness o si se firma el número entero o y (tal vez) es más rápido que con el módulo de estructura, sino:

b = (8, 1, 0, 0) 
sum(b[i] << (i * 8) for i in range(4)) 
+0

solo como referencia esto es para little-endian y posiblemente se pueda mejorar ligeramente como 'suma (b [i] << (i * 8) para i en rango (len (b)))' para permitir la entrada de tamaño variable o 'suma (respuesta [i] << (i * 8) para i en rango (len (respuesta) -1)) 'para el OP. – Caltor

+0

@Ad__ Me gusta esta solución, ya que es probablemente más rápido que struct.unpack y, a diferencia de ese método, no requiere importar un módulo. ¿Podrías proporcionar una versión que pueda manejar a Big-Endian, por favor? – Caltor

4

También podría hacer el uso del módulo gama

import struct 
from array import array 
response = (0, 0, 117, 143, 6) 
a = array('B', response[:4]) 
struct.unpack('>I', a) 

(30095L,) 
+0

Probé este enfoque también, pero decidí ir con una lista de comprensión y join(), para evitar importar otro módulo, y como ninguno de los dos estaba particularmente claro, desafortunadamente. – Jay

+0

Olvidé que struct puede empacar arrays [respuesta fija], lo que creo que hace que esta versión sea ligeramente mejor que la comp de la lista. – JimB

+0

Bien, no sabía que podía hacer eso, lo echaba de menos en los documentos. Lo agregaré a mi respuesta también como alternativa. – Jay

0

Cómo sobre el uso de la función de mapa:

a = (0, 0, 117, 143, 6) 
b = [] 
map(b.append, a) 

Además, no sé si esto es lo que buscas:

response = (0, 0, 117, 143, 6) 
response[0:4] 
3

Esto se parece a un trabajo para reducir!

Lo que básicamente necesita es hacer un cambio de bit un byte a la vez y luego agregar (agregar) el siguiente byte en la secuencia.

a = (0, 0, 117, 143, 6) 
reduce(lambda x, y: (x<<8) + y, a) 
7704326 
+0

-1 Lea la pregunta. Hay CINCO bytes. El OP dice que los primeros 4 son un int de 32 bits. El último es un porcentaje (6%). –

+0

@John: creo que es solo un pequeño error, simplemente cambie en la segunda línea '' a'' por '' a [: 4] '' y el código funciona según lo necesite el OP (al menos si big endian está destinado) No hay necesidad de rechazar esto directamente. –

+0

@Kristian cualquier posibilidad de una versión de esto para little endian por favor? – Caltor

Cuestiones relacionadas