struct — Estrutucturas binarias de datos¶
Propósito: | Convierte entre canedas y datos binarios. |
---|
El módulo struct
incluye funciones para convertir entre cadenas de bytes y
tipos de datos nativos de Python, como números y cadenas.
Funciones frente a clase Struct¶
Un conjunto de funciones a nivel de módulo está disponible para trabajar con
valores estructurados, así como la clase Struct
. Especificadores de
formato se convierten de su formato de cadena a una representación compilada,
similar a la forma en que se manejan las expresiones regulares. La conversión
requiere algunos recursos, por lo que suele ser más eficiente hacerla una vez
cuando se crea una instancia Struct
y llamar métodos en la instancia en
lugar de usar las funciones a nivel de módulo. Todos los ejemplos que siguen
usan la clase Struct
.
Empaquetando y desempaquetando¶
Structs admiten empaquetar datos en cadenas y desempaquetar datos de cadenas utilizando especificadores de formato compuestos por caracteres que representan el tipo de datos y los indicadores opcionales de conteo y extremidad (endianness). Referete a la documentación estándar de la biblioteca para obtener una lista completa de especificadores de formato compatibles.
En este ejemplo, el especificador solicita un valor entero o entero largo, una cadena de dos bytes y un número de coma flotante. Los espacios en el especificador de formato se incluyen para separar los indicadores de tipo, y son ignorados cuando se compila el formato.
import struct
import binascii
values = (1, 'ab'.encode('utf-8'), 2.7)
s = struct.Struct('I 2s f')
packed_data = s.pack(*values)
print('Original values:', values)
print('Format string :', s.format)
print('Uses :', s.size, 'bytes')
print('Packed Value :', binascii.hexlify(packed_data))
El ejemplo convierte el valor empaquetado a una secuencia de bytes
hexadecimales para imprimir con binascii.hexlify()
, ya que algunos de los
caracteres son nulos.
$ python3 struct_pack.py
Original values: (1, b'ab', 2.7)
Format string : b'I 2s f'
Uses : 12 bytes
Packed Value : b'0100000061620000cdcc2c40'
Utiliza unpack()
para extraer datos de su representación empaquetada.
import struct
import binascii
packed_data = binascii.unhexlify(b'0100000061620000cdcc2c40')
s = struct.Struct('I 2s f')
unpacked_data = s.unpack(packed_data)
print('Unpacked Values:', unpacked_data)
Pasar el valor empaquetado a unpack()
, devuelve básicamente los mismos
valores (ten en cuenta la discrepancia en el valor del punto flotante).
$ python3 struct_unpack.py
Unpacked Values: (1, b'ab', 2.700000047683716)
Extremidad¶
Por defecto, se codifican los valores utilizando la noción de biblioteca C nativa de extremidad. Es fácil anular esa elección proporcionando una directiva de extremidad explícita en la cadena de formato.
import struct
import binascii
values = (1, 'ab'.encode('utf-8'), 2.7)
print('Original values:', values)
endianness = [
('@', 'native, native'),
('=', 'native, standard'),
('<', 'little-endian'),
('>', 'big-endian'),
('!', 'network'),
]
for code, name in endianness:
s = struct.Struct(code + ' I 2s f')
packed_data = s.pack(*values)
print()
print('Format string :', s.format, 'for', name)
print('Uses :', s.size, 'bytes')
print('Packed Value :', binascii.hexlify(packed_data))
print('Unpacked Value :', s.unpack(packed_data))
the table below enumera los
especificadores de orden de bytes utilizados por Struct
.
Código | Significado |
---|---|
@ |
Orden nativo |
= |
Estándar nativo |
< |
little-endian |
> |
big-endian |
! |
Orden de red |
$ python3 struct_endianness.py
Original values: (1, b'ab', 2.7)
Format string : b'@ I 2s f' for native, native
Uses : 12 bytes
Packed Value : b'0100000061620000cdcc2c40'
Unpacked Value : (1, b'ab', 2.700000047683716)
Format string : b'= I 2s f' for native, standard
Uses : 10 bytes
Packed Value : b'010000006162cdcc2c40'
Unpacked Value : (1, b'ab', 2.700000047683716)
Format string : b'< I 2s f' for little-endian
Uses : 10 bytes
Packed Value : b'010000006162cdcc2c40'
Unpacked Value : (1, b'ab', 2.700000047683716)
Format string : b'> I 2s f' for big-endian
Uses : 10 bytes
Packed Value : b'000000016162402ccccd'
Unpacked Value : (1, b'ab', 2.700000047683716)
Format string : b'! I 2s f' for network
Uses : 10 bytes
Packed Value : b'000000016162402ccccd'
Unpacked Value : (1, b'ab', 2.700000047683716)
Búferes¶
Trabajar con datos binarios empaquetados generalmente se reserva para
situaciones sensibles al rendimiento o al pasar datos adentro y afuera de
módulos de extensión. Estos casos se pueden optimizar evitando la sobrecarga
de asignar un nuevo búfer para cada estructura empaquetada. Los métodos
pack_into()
y unpack_from()
admiten la escritura directa a búferes
preasignados.
import array
import binascii
import ctypes
import struct
s = struct.Struct('I 2s f')
values = (1, 'ab'.encode('utf-8'), 2.7)
print('Original:', values)
print()
print('ctypes string buffer')
b = ctypes.create_string_buffer(s.size)
print('Before :', binascii.hexlify(b.raw))
s.pack_into(b, 0, *values)
print('After :', binascii.hexlify(b.raw))
print('Unpacked:', s.unpack_from(b, 0))
print()
print('array')
a = array.array('b', b'\0' * s.size)
print('Before :', binascii.hexlify(a))
s.pack_into(a, 0, *values)
print('After :', binascii.hexlify(a))
print('Unpacked:', s.unpack_from(a, 0))
El atributo size` de Struct
nos dice qué tan grande necesita ser el
búfer.
$ python3 struct_buffers.py
Original: (1, b'ab', 2.7)
ctypes string buffer
Before : b'000000000000000000000000'
After : b'0100000061620000cdcc2c40'
Unpacked: (1, b'ab', 2.700000047683716)
array
Before : b'000000000000000000000000'
After : b'0100000061620000cdcc2c40'
Unpacked: (1, b'ab', 2.700000047683716)
Ver también
- Documentación de la biblioteca estándar para struct
- Notas para portar Python 2 a 3 para struct
array
– El móduloarray
, para trabajar con secuencias de valores de tipo fijo.binascii
– El módulobinascii
, para producir representaciones ASCII de datos binarios.- Wikipedia: Endianness – Explicación del orden de bytes y extremidad en la codificación.