struct — Interpret bytes as packed binary data

Código fuente: Lib/struct.py


Este módulo convierte entre valores de Python y estructuras de C representadas como objetos de Python bytes. Las cadenas de formato compacto describen las conversiones previstas hacia/desde valores de Python. Las funciones y objetos del módulo se pueden utilizar para dos aplicaciones en gran medida distintas, el intercambio de datos con fuentes externas (archivos o conexiones de red) o la transferencia de datos entre la aplicación de Python y la capa de C.

Nota

Cuando no se proporciona ningún carácter de prefijo, el modo nativo es el predeterminado. Empaqueta o desempaqueta datos según la plataforma y el compilador en el que se creó el intérprete de Python. El resultado de empaquetar una estructura C determinada incluye bytes de relleno que mantienen la alineación adecuada para los tipos C involucrados; asimismo, se tiene en cuenta la alineación al desempaquetar. Por el contrario, cuando se comunican datos entre fuentes externas, el programador es responsable de definir el orden de bytes y el relleno entre elementos. Ver Orden de bytes, tamaño y alineación para más detalles.

Varias funciones struct (y métodos de Struct) toman un argumento buffer. Esto hace referencia a los objetos que implementan Protocolo búfer y proporcionan un búfer de lectura o de lectura/escritura. Los tipos más comunes utilizados para ese propósito son bytes y bytearray, pero muchos otros tipos que se pueden ver como una lista de bytes implementan el protocolo de búfer, para que se puedan leer/rellenar sin necesidad de copiar a partir de un objeto bytes.

Funciones y excepciones

El módulo define la siguiente excepción y funciones:

exception struct.error

Excepción lanzada en varias ocasiones; el argumento es una string que describe lo que está mal.

struct.pack(format, v1, v2, ...)

Retorna un objeto bytes que contiene los valores v1, v2, … empaquetado de acuerdo con la cadena de formato format. Los argumentos deben coincidir exactamente con los valores requeridos por el formato.

struct.pack_into(format, buffer, offset, v1, v2, ...)

Empaqueta los valores v1, v2, … de acuerdo con la cadena de formato format y escribe los bytes empaquetados en el búfer de escritura buffer comenzando en la posición offset. Nota: offset es un argumento obligatorio.

struct.unpack(format, buffer)

Desempaqueta del búfer buffer (normalmente empaquetado por pack(format, ...)) según la cadena de formato format. El resultado es una tupla incluso si contiene un solo elemento. El tamaño del búfer en bytes debe coincidir con el tamaño requerido por el formato, como se refleja en calcsize().

struct.unpack_from(format, /, buffer, offset=0)

Desempaqueta del buffer comenzando en la posición offset, según la cadena de formato format. El resultado es una tupla incluso si contiene un solo elemento. El tamaño del búfer en bytes, comenzando en la posición offset, debe tener al menos el tamaño requerido por el formato, como se refleja en calcsize().

struct.iter_unpack(format, buffer)

Desempaqueta de manera iterativa desde el búfer buffer según la cadena de formato format. Esta función retorna un iterador que leerá fragmentos de igual tamaño desde el búfer hasta que se haya consumido todo su contenido. El tamaño del búfer en bytes debe ser un múltiplo del tamaño requerido por el formato, como se refleja en calcsize().

Cada iteración produce una tupla según lo especificado por la cadena de formato.

Added in version 3.4.

struct.calcsize(format)

Retorna el tamaño de la estructura (y, por lo tanto, del objeto bytes generado por pack(format, ...)) correspondiente a la cadena de formato format.

Cadenas de formato

Las cadenas de formato describen el diseño de los datos cuando empaquetan y desempaquetan datos. Se construyen a partir caracteres de formato, que especifican el tipo de datos que se empaquetan/desempaquetan. Además, los caracteres especiales controlan el orden de bytes, tamaño y alineación. Cada cadena de formato consta de un carácter de prefijo opcional que describe las propiedades generales de los datos y uno o más caracteres de formato que describen los valores de datos actuales y el relleno.

Orden de bytes, tamaño y alineación

Por defecto, los tipos C se representan en el formato nativo y el orden de bytes de la máquina, y se alinean correctamente omitiendo bytes de relleno si es necesario (según las reglas utilizadas por el compilador de C). Se elige este comportamiento para que los bytes de una estructura empaquetada correspondan correctamente al diseño de memoria de la estructura C correspondiente. El uso de ordenamiento y relleno de bytes nativos o formatos estándar depende de la aplicación.

Como alternativa, el primer carácter de la cadena de formato se puede utilizar para indicar el orden de bytes, el tamaño y la alineación de los datos empaquetados, según la tabla siguiente:

Carácter

Orden de bytes

Tamaño

Alineamiento

@

nativo

nativo

nativo

=

nativo

standard

none

<

little-endian

standard

none

>

big-endian

standard

none

!

red (= big-endian)

standard

none

Si el primer carácter no es uno de estos, se asume '@'.

Nota

The number 1023 (0x3ff in hexadecimal) has the following byte representations:

  • 03 ff in big-endian (>)

  • ff 03 in little-endian (<)

Python example:

>>> import struct
>>> struct.pack('>h', 1023)
b'\x03\xff'
>>> struct.pack('<h', 1023)
b'\xff\x03'

El orden de bytes nativo es big-endian o little-endian, dependiendo del sistema host. Por ejemplo, Intel x86, AMD64 (x86-64) y Apple M1 son little-endian; IBM z y muchas arquitecturas heredadas son big-endian; ARM e Intel Itanium tienen la propiedad de trabajar con ambos formatos (middle-endian). Utiliza sys.byteorder para comprobar la endianness («extremidad») de tu sistema.

El tamaño y la alineación nativos se determinan mediante la expresión sizeof del compilador de C. Esto siempre se combina con el orden de bytes nativo.

El tamaño estándar depende únicamente del carácter de formato; ver la tabla en la sección Caracteres de formato.

Nótese la diferencia entre '@' y '=' : ambos utilizan el orden de bytes nativo, pero el tamaño y la alineación de este último está estandarizado.

La forma '!' representa el orden de bytes en la red, el cuál siempre es big-endian tal como se define en IETF RFC 1700.

No hay manera de indicar el orden de bytes no nativo (forzar el intercambio de bytes); utiliza la elección adecuada de '<' o '>'.

Notas:

  1. El relleno solo se agrega automáticamente entre los miembros sucesivos de la estructura. No se agrega ningún relleno al principio o al final de la estructura codificada.

  2. No se añade ningún relleno cuando se utiliza el tamaño y la alineación no nativos, por ejemplo, con “<”, “>”, “=” y “!”.

  3. Para alinear el final de una estructura con el requisito de alineación de un tipo determinado, termina el formato con el código de ese tipo con un conteo repetido de ceros. Véase Ejemplos.

Caracteres de formato

Los caracteres de formato tienen el siguiente significado; la conversión entre los valores de C y Python debe ser obvia dados sus tipos. La columna “Tamaño estándar” hace referencia al tamaño del valor empaquetado en bytes cuando se utiliza el tamaño estándar; es decir, cuando la cadena de formato comienza con uno de '<', '>', '!' o '='. Cuando se utiliza el tamaño nativo, el tamaño del valor empaquetado depende de la plataforma.

Formato

Tipo C

Tipo Python

Tamaño estándar

Notas

x

byte de relleno

sin valor

(7)

c

char

bytes de longitud 1

1

b

signed char

integer

1

(1), (2)

B

unsigned char

integer

1

(2)

(2)

_Bool

bool

1

(1)

h

short

integer

2

(2)

H

unsigned short

integer

2

(2)

i

int

integer

4

(2)

I

unsigned int

integer

4

(2)

l

long

integer

4

(2)

L

unsigned long

integer

4

(2)

q

long long

integer

8

(2)

Q

unsigned long long

integer

8

(2)

n

ssize_t

integer

(3)

N

size_t

integer

(3)

e

(6)

float

2

(4)

f

float

float

4

(4)

d

double

float

8

(4)

s

char[]

bytes

(9)

p

char[]

bytes

(8)

P

void*

integer

(5)

Distinto en la versión 3.3: Soporte añadido para los formatos 'n' y 'N'.

Distinto en la versión 3.6: Soporte añadido para el formato 'e'.

Notas:

  1. The '?' conversion code corresponds to the _Bool type defined by C standards since C99. In standard mode, it is represented by one byte.

  2. Al intentar empaquetar un no entero mediante cualquiera de los códigos de conversión de enteros, si el no entero tiene un método __index__(), se llama a ese método para convertir el argumento en un entero antes de empaquetar.

    Distinto en la versión 3.2: Agregado el uso del método __index__() para los no enteros.

  3. Los códigos de conversión 'n' y 'N' solo están disponibles para el tamaño nativo (seleccionado como predeterminado o con el carácter de orden de bytes '@'). Para el tamaño estándar, puedes usar cualquiera de los otros formatos enteros que se ajusten a tu aplicación.

  4. Para los códigos de conversión 'f', 'd' y 'e', la representación empaquetada utiliza el formato IEEE 754 binary32, binary64 o binary16 (para 'f', 'd' o 'e' respectivamente), independientemente del formato de punto flotante utilizado por la plataforma.

  5. El carácter de formato 'P' solo está disponible para el orden nativo de bytes (seleccionado como predeterminado o con el carácter de orden de bytes '@'). El carácter de orden de bytes '=' elige utilizar el orden little- o big-endian basado en el sistema host. El módulo struct no interpreta esto como un orden nativo, por lo que el formato 'P' no está disponible.

  6. El tipo IEEE 754 binary16 «half precision» se introdujo en la revisión de 2008 del IEEE 754 estándar. Tiene un bit de signo, un exponente de 5 bits y una precisión de 11 bits (con 10 bits almacenados explícitamente) y puede representar números entre aproximadamente 6.1e-05 y 6.5e+04 con total precisión. Este tipo no es ampliamente compatible con los compiladores de C: en un equipo típico, un unsigned short se puede usar para el almacenamiento, pero no para las operaciones matemáticas. Consulte la página de Wikipedia en el formato de punto flotante de media precisión para obtener más información.

  7. Al empaquetar, 'x' inserta un byte NUL.

  8. El carácter de formato 'p' codifica una «cadena de Pascal», lo que significa una cadena de longitud variable corta almacenada en un número fijo de bytes, dado por el recuento. El primer byte almacenado es el valor mínimo entre la longitud de la cadena o 255. A continuación se encuentran los bytes de la cadena. Si la cadena pasada a pack() es demasiado larga (más larga que la cuenta menos 1), solo se almacenan los bytes iniciales count-1 de la cadena. Si la cadena es más corta que count-1, se rellena con bytes nulos para que se utilicen exactamente los bytes de recuento en total. Tenga en cuenta que para unpack(), el carácter de formato 'p' consume bytes count, pero que la cadena retornada nunca puede contener más de 255 bytes.

  9. Para el carácter de formato 's', el recuento se interpreta como la longitud de los bytes, no un recuento de repetición como para los otros caracteres de formato; por ejemplo, '10s' significa una sola cadena de 10 bytes asignada hacia o desde una sola cadena de bytes de Python, mientras que '10c' significa 10 elementos de caracteres separados de un byte (por ejemplo, cccccccccc) asignada hacia o desde diez objetos de bytes de Python diferentes. (Ver Ejemplos para una demostración concreta de la diferencia.) Si no se da un recuento, el valor predeterminado es 1. Para el empaquetado, la cadena es truncada o rellenada con bytes nulos según corresponda para que se ajuste. Para desempaquetar, el objeto bytes resultante siempre tiene exactamente el número especificado de bytes. Como caso especial, '0s' significa una sola cadena vacía (mientras que '0c' significa 0 caracteres).

Un carácter de formato puede ir precedido de un número de recuento que repite tantas veces el carácter. Por ejemplo, la cadena de formato '4h' significa exactamente lo mismo que 'hhhh' .

Se omiten los caracteres de espacio entre formatos; sin embargo, un recuento y su formato no deben contener espacios en blanco.

Al empaquetar un valor x utilizando uno de los formatos enteros ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'), si x está fuera de un rango válido para ese formato, entonces se lanza la excepción struct.error.

Distinto en la versión 3.1: Anteriormente, algunos de los formatos enteros ajustaban los valores fuera de rango y lanzaban DeprecationWarning en vez de struct.error.

Para el carácter de formato '?', el valor retornado es True o False. Al empaquetar, se utiliza el valor verdadero del objeto del argumento. Se empaquetará 0 o 1 en la representación bool nativa o estándar, y cualquier valor distinto de cero será True al desempaquetar.

Ejemplos

Nota

Los ejemplos de orden de bytes nativos (designados por el prefijo de formato '@' o la falta de cualquier carácter de prefijo) pueden no coincidir con lo que produce la máquina del lector, ya que eso depende de la plataforma y el compilador.

Empaqueta y desempaqueta enteros de tres tamaños diferentes, utilizando el orden big endian:

>>> from struct import *
>>> pack(">bhl", 1, 2, 3)
b'\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('>bhl', b'\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('>bhl')
7

Intenta empaquetar un entero que es demasiado grande para el campo definido:

>>> pack(">h", 99999)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
struct.error: 'h' format requires -32768 <= number <= 32767

Demuestra la diferencia entre los caracteres de formato 's' y 'c':

>>> pack("@ccc", b'1', b'2', b'3')
b'123'
>>> pack("@3s", b'123')
b'123'

Los campos desempaquetados se pueden nombrar asignándolos a variables o ajustando el resultado en una tupla con nombre:

>>> record = b'raymond   \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)

>>> from collections import namedtuple
>>> Student = namedtuple('Student', 'name serialnum school gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)

El orden de los caracteres de formato puede afectar el tamaño en el modo nativo, ya que el relleno está implícito. En el modo estándar, el usuario es responsable de insertar el relleno que desee. Toma en cuenta que en la primera llamada pack a continuación se agregaron tres bytes NUL después del '#' empaquetado para alinear el siguiente entero en un límite de cuatro bytes. En este ejemplo, el resultado se produjo en una máquina little endian:

>>> pack('@ci', b'#', 0x12131415)
b'#\x00\x00\x00\x15\x14\x13\x12'
>>> pack('@ic', 0x12131415, b'#')
b'\x15\x14\x13\x12#'
>>> calcsize('@ci')
8
>>> calcsize('@ic')
5

El siguiente formato 'llh0l' especifica dos bytes de relleno al final, suponiendo que los tipos longs están alineados en los límites de 4 bytes:

>>> pack('@llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'

Ver también

Módulo array

Almacenamiento binario empaquetado de datos homogéneos.

Módulo json

Codificador y decodificador JSON.

Módulo pickle

Serialización de objetos Python.

Aplicaciones

Existen dos aplicaciones principales para el módulo struct, el intercambio de datos entre el código Python y C dentro de una aplicación u otra aplicación compilada usando el mismo compilador (formatos nativos) y el intercambio de datos entre aplicaciones usando un diseño de datos acordado (formatos estándar). En términos generales, las cadenas de formato construidas para estos dos dominios son distintas.

Formatos nativos

Al construir cadenas de formato que imitan diseños nativos, el compilador y la arquitectura de la máquina determinan el orden y el relleno de los bytes. En tales casos, se debe utilizar el carácter de formato @ para especificar el orden de bytes nativo y el tamaño de los datos. Los bytes de relleno internos normalmente se insertan automáticamente. Es posible que se necesite un código de formato de repetición cero al final de una cadena de formato para redondear hasta el límite de bytes correcto para una alineación adecuada de fragmentos de datos consecutivos.

Considera estos dos ejemplos sencillos (en una máquina little-endian de 64 bits):

>>> calcsize('@lhl')
24
>>> calcsize('@llh')
18

Los datos no se rellenan hasta un límite de 8 bytes al final de la segunda cadena de formato sin el uso de relleno adicional. Un código de formato de repetición cero resuelve ese problema:

>>> calcsize('@llh0l')
24

El código de formato 'x' se puede utilizar para especificar la repetición, pero para formatos nativos es mejor utilizar un formato de repetición cero como '0l'.

De forma predeterminada, se utiliza el orden y la alineación de bytes nativos, pero es mejor ser explícito y utilizar el carácter de prefijo '@'.

Formatos estándar

Cuando intercambia datos más allá de su proceso, como redes o almacenamiento, sé preciso. Especifica el orden de bytes, el tamaño y la alineación exactos. No asumas que coinciden con el orden nativo de una máquina en particular. Por ejemplo, el orden de los bytes de la red es big-endian, mientras que muchas CPU populares son little-endian. Al definir esto explícitamente, el usuario no necesita preocuparse por las especificaciones de la plataforma en la que se ejecuta su código. El primer carácter normalmente debería ser < o > (o !). El relleno es responsabilidad del programador. El carácter de formato de repetición cero no funcionará. En su lugar, el usuario debe agregar explícitamente 'x' bytes de relleno donde sea necesario. Revisando los ejemplos de la sección anterior, tenemos:

>>> calcsize('<qh6xq')
24
>>> pack('<qh6xq', 1, 2, 3) == pack('@lhl', 1, 2, 3)
True
>>> calcsize('@llh')
18
>>> pack('@llh', 1, 2, 3) == pack('<qqh', 1, 2, 3)
True
>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
24
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
True

No se garantiza que los resultados anteriores (ejecutados en una máquina de 64 bits) coincidan cuando se ejecutan en diferentes máquinas. Por ejemplo, los siguientes ejemplos se ejecutaron en una máquina de 32 bits:

>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
12
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
False

Clases

El módulo struct también define el siguiente tipo:

class struct.Struct(format)

Retorna un nuevo objeto Struct que escribe y lee datos binarios según la cadena de formato format. Crear un objeto Struct una vez y llamar a sus métodos es más eficaz que llamar a las funciones a nivel de módulo con el mismo formato, ya que la cadena de formato solo se compila una vez.

Nota

Las versiones compiladas de las cadenas de formato más recientes pasadas a las funciones de nivel de módulo se almacenan en caché, por lo que los programas que utilizan solo unas pocas cadenas de formato no necesitan preocuparse por volver a usar una sola instancia Struct.

Los objetos Struct compilados admiten los siguientes métodos y atributos:

pack(v1, v2, ...)

Idéntico a la función pack(), utilizando el formato compilado. (len(result) será igual a size.)

pack_into(buffer, offset, v1, v2, ...)

Idéntico a la función pack_into(), utilizando el formato compilado.

unpack(buffer)

Idéntico a la función unpack(), utilizando el formato compilado. El tamaño del búfer en bytes debe ser igual a size.

unpack_from(buffer, offset=0)

Idéntico a la función unpack_from(), utilizando el formato compilado. El tamaño del búfer en bytes, comenzando en la posición offset, debe ser al menos size.

iter_unpack(buffer)

Idéntico a la función iter_unpack(), utilizando el formato compilado. El tamaño del búfer en bytes debe ser un múltiplo de size.

Added in version 3.4.

format

Cadena de formato utilizada para construir este objeto Struct.

Distinto en la versión 3.7: El tipo de cadena de formato es ahora str en lugar de bytes.

size

El tamaño calculado de la estructura (y, por lo tanto, del objeto bytes generado por el método pack()) correspondiente a format.

Distinto en la versión 3.13: The repr() of structs has changed. It is now:

>>> Struct('i')
Struct('i')