El módulo struct de Python se utiliza para proporcionar una interfaz pitónica simple para acceder y manipular el tipo de datos de estructura de C. Esto puede ser una herramienta útil si alguna vez necesitas tratar con código C y no tienes tiempo para escribir herramientas en C ya que es un lenguaje de bajo nivel.
Este módulo puede convertir valores de Python a una estructura de C y viceversa. La estructura de C se utiliza como un objeto de bytes de Python ya que no hay nada llamado objeto en C; sólo estructuras de datos del tamaño de un byte.
Entendamos cómo podemos utilizar este módulo para tener una interfaz de Python a las estructuras de C.
Métodos del módulo struct de Python
En este módulo, ya que nos ocupan las estructuras de C, vamos a ver algunas de las funciones que nos proporciona este módulo.
Estructura.pack()
Se utiliza para empaquetar elementos en una cadena de bytes de Python (objeto byte). Como el modo de almacenamiento se basa en bytes, los programas basados en C pueden utilizar la salida de pack()
, de un programa de Python.
Formato: struct.pack(format, v1, v2, …)
v1
v2
, … son los valores que se empaquetarán en el objeto byte. Representan los valores de los campos de la estructura C. Como una estructura C que tiene campos n
debe tener exactamente valores n
, los argumentos deben coincidir exactamente con los valores requeridos por el formato.
Aquí, format
se refiere al formato del empaquetado. Esto es necesario ya que necesitamos especificar el tipo de datos de la cadena de bytes, ya que se utiliza con el código C. La siguiente tabla lista los valores más comunes para format
. Necesitamos un formato por valor para especificar su tipo de datos.
Formato | C Tipo de datos | Tipo Python | c |
char | una cadena de longitud 1 |
? |
Bool | bool |
h |
corto | integro |
l |
largo | integro |
i |
int | integro |
f |
float | float |
d |
double | float | s |
char | string |
Entendamos esto usando algunos ejemplos.
El siguiente snippet almacena los 3 enteros 1, 2 y 3 en un objeto byte usando pack()
. Como el tamaño de un entero es de 4 bytes en mi máquina, se ven 3 bloques de 4 bytes, que corresponden a 3 enteros en C.
import struct# We pack 3 integers, so 'iii' is requiredvariable = struct.pack('iii', 1, 2, 3)print(type(variable), variable)variable_2 = struct.pack('iic', 1, 2, b'A')print('\n', variable_2)
Salida
<class 'bytes'> b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'b'\x01\x00\x00\x00\x02\x00\x00\x00A'
Si no se pasa el tipo adecuado, la excepción struct.error
será lanzada por el módulo struct de Python.
import struct# Error!! Incorrect datatype assignmentvariable = struct.pack('ccc', 1, 2, 3)print(type(variable), variable)
Salida
struct.error: char format requires a bytes object of length 1
struct.unpack()
Esta función del módulo struct de Python, desempaqueta el valor empaquetado en su representación original según un formato apropiado. Esto devuelve una tupla de tamaño igual al número de valores pasados desde que se desempaqueta el objeto byte para dar los elementos.
Formato: struct.unpack(format, string)
Esto desempaqueta el byte string
según el especificador de formato format
.
Esto es lo contrario de struct.pack()
. Tomemos una de las antiguas cadenas de bytes que produjimos usando eso e intentemos recuperar los valores de python que se le pasaron usando unpack()
.
import structbyte_str = b'\x01\x00\x00\x00\x02\x00\x00\x00A'# Using the same format specifier as before, since# we want to get Python values for the same byte-stringtuple_vals = struct.unpack('iic', byte_str)print(tuple_vals)
Salida
(1, 2, b'A')
Como puedes ver, efectivamente, podemos obtener el paquete de nuestros antiguos valores de Python de esta tupla, siempre que utilicemos el mismo especificador de formato tanto para pack()
como para unpack()
.
struct.calcsize()
Esta función devuelve el tamaño total de la representación String del struct utilizando un especificador de formato dado, para recuperar los tipos de los datos y calcular el tamaño.
Formato: struct.calcsize(fmt)
import structprint('C Integer Size in Bytes:', struct.calcsize('i'))print('Size of 3 characters in Bytes:', struct.calcsize('ccc'))
Salida
C Integer Size in Bytes: 4Size of 3 characters in Bytes: 3
struct.pack_into()
Esta función se utiliza para empaquetar valores en un buffer de cadena de Python, disponible en el módulo ctypes
.
Formato: struct.pack_into(fmt, buffer, offset, v1, v2, …)
Aquí, fmt
se refiere al especificador de formato, como siempre. buffer
es el buffer de cadena que ahora contendrá los valores empaquetados, especificados. También se puede especificar una offset
ubicación desde la dirección base desde la que se producirá el empaquetado.
Esto no devuelve ningún valor, y simplemente almacena los valores en la cadena buffer
.
import struct import ctypes # We will create a string buffer having a size# equal to that of a struct with 'iic' values.buf_size = struct.calcsize('iic') # Create the string bufferbuff = ctypes.create_string_buffer(buf_size) # struct.pack() returns the packed data struct.pack_into('iic', buff, 0, 1, 2, b'A')print(buff)# Display the contents of the bufferprint(buff)
Salida
<ctypes.c_char_Array_9 object at 0x7f4bccef1040>b'\x01\x00\x00\x00\x02\x00\x00\x00A'
En efecto, obtenemos nuestros valores empaquetados en la cadena del buffer.
struct.unpack_from()
De forma similar a unpack()
, existe una contrapartida para desempaquetar valores de una cadena del buffer. Esto hace lo contrario de struct.pack_into()
.
Formato: struct.unpack_from(fmt, buffer, offset)
Esto devolverá una tupla de valores, similar a struct.unpack()
.
import struct import ctypes # We will create a string buffer having a size# equal to that of a struct with 'iic' values.buf_size = struct.calcsize('iic') # Create the string bufferbuff = ctypes.create_string_buffer(buf_size) # struct.pack() returns the packed data struct.pack_into('iic', buff, 0, 1, 2, b'A')print(struct.unpack_from('iic', buff, 0))
Salida
(1, 2, b'A')
Conclusión
En este artículo, hemos aprendido a utilizar el módulo struct de Python para tratar con objetos de estructura de tipo C.