De Python struct module wordt gebruikt om een eenvoudige Python interface te bieden voor het benaderen en manipuleren van C’s structure datatype. Dit kan een handig hulpmiddel zijn als je ooit met C-code moet werken en geen tijd hebt om hulpmiddelen in C te schrijven omdat het een taal op laag niveau is.
Deze module kan Python-waarden converteren naar een C-structuur en vice-versa. De C structuur wordt gebruikt als een Python bytes object omdat er niets is dat een object wordt genoemd in C; alleen datastructuren ter grootte van een byte.
Laten we eens begrijpen hoe we deze module kunnen gebruiken om een Python interface te hebben voor C structuren.
Methoden van de Python struct-module
In deze module houden we ons bezig met C-structuren, dus laten we eens kijken naar enkele functies die deze module ons biedt.
struct.pack()
Dit wordt gebruikt om elementen in een Python byte-string (byte-object) in te pakken. Aangezien de opslagwijze op bytes is gebaseerd, kunnen C-gebaseerde programma’s de uitvoer van pack()
, vanuit een Python-programma gebruiken.
Formaat: struct.pack(format, v1, v2, …)
v1
v2
, … zijn de waarden die in het byte-object zullen worden verpakt. Zij vertegenwoordigen de veldwaarden voor de C structuur. Aangezien een C-structuur met n
velden precies n
waarden moet hebben, moeten de argumenten precies overeenkomen met de waarden die door het formaat worden vereist.
Hier verwijst format
naar het formaat van de verpakking. Dit is nodig omdat we het datatype van de byte-string moeten specificeren, zoals die wordt gebruikt in C-code. De onderstaande tabel geeft de meest voorkomende waarden voor format
. We hebben één formaat per waarde nodig om het datatype aan te geven.
Formaat | C Datatype | Python type |
c |
char | een string van lengte 1 |
? |
_Bool | bool |
h |
short | integer |
l |
long | heel getal |
i |
int | geheel getal |
f |
float | float |
d |
dubbel | float |
s |
char | string |
Laten we dit eens begrijpen aan de hand van enkele voorbeelden.
Het onderstaande knipsel slaat de 3 gehele getallen 1, 2 en 3 op in een byte-object met behulp vanpack()
. Aangezien de grootte van een geheel getal 4 bytes is op mijn machine, zie je 3 blokken van 4 bytes, die overeenkomen met 3 gehele getallen in 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)
Uitvoer
<class 'bytes'> b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'b'\x01\x00\x00\x00\x02\x00\x00\x00A'
Als niet het juiste type wordt doorgegeven, wordt de exception struct.error
opgeworpen door de Python struct-module.
import struct# Error!! Incorrect datatype assignmentvariable = struct.pack('ccc', 1, 2, 3)print(type(variable), variable)
Output
struct.error: char format requires a bytes object of length 1
struct.unpack()
Deze functie van de Python struct-module pakt de ingepakte waarde uit in zijn oorspronkelijke weergave volgens een geschikt formaat. Dit geeft een tuple terug van grootte gelijk aan het aantal waarden dat is doorgegeven sinds het byte-object is uitgepakt om de elementen te geven.
Formaat: struct.unpack(format, string)
Dit pakt de byte string
uit volgens de format
format specifier.
Dit is het omgekeerde van struct.pack()
. Laten we een van de oude byte-strings nemen die we daarmee hebben geproduceerd en proberen de python-waarden terug te krijgen die we eraan hebben doorgegeven met 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)
Uitvoer
(1, 2, b'A')
Zoals je kunt zien, inderdaad, kunnen we onze oude Python-waarden uit deze tuple halen, mits we dezelfde format specifier gebruiken voor zowel pack()
als unpack()
.
struct.calcsize()
Deze functie retourneert de totale grootte van de String representatie van de struct met behulp van een gegeven format specifier, om de types van de data op te halen en de grootte te berekenen.
Formaat: struct.calcsize(fmt)
import structprint('C Integer Size in Bytes:', struct.calcsize('i'))print('Size of 3 characters in Bytes:', struct.calcsize('ccc'))
Uitvoer
C Integer Size in Bytes: 4Size of 3 characters in Bytes: 3
struct.pack_into()
Deze functie wordt gebruikt om waarden in te pakken in een Python-stringbuffer, die beschikbaar is in de ctypes
-module.
Formaat: struct.pack_into(fmt, buffer, offset, v1, v2, …)
Hier verwijst fmt
naar de format specifier, zoals altijd. buffer
is de string buffer die nu de verpakte waarden zal bevatten, gespecificeerd. U kunt ook een offset
locatie opgeven vanaf het basisadres van waaruit het verpakken zal plaatsvinden.
Dit geeft geen waarde terug, maar slaat de waarden gewoon op in de buffer
string.
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)
Output
<ctypes.c_char_Array_9 object at 0x7f4bccef1040>b'\x01\x00\x00\x00\x02\x00\x00\x00A'
Inderdaad krijgen we onze ingepakte waarden in de bufferstring.
struct.unpack_from()
Gelijk aan unpack()
, bestaat er een tegenhanger voor het uitpakken van waarden uit een bufferstring. Dit doet het omgekeerde van struct.pack_into()
.
Opmaak: struct.unpack_from(fmt, buffer, offset)
Dit levert een tupel van waarden op, vergelijkbaar met 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))
Uitvoer
(1, 2, b'A')
Conclusie
In dit artikel hebben we geleerd hoe we de Python struct-module kunnen gebruiken om met C-type structuurobjecten om te gaan.