Back to Python
2025-12-116 min read

Structs (Python Programming)

Learn Structs (Python Programming) step by step with clear examples and exercises.

Title: Python Structs - Master Complex Data Structures with Practical Examples and Common Mistakes

Why This Matters

In Python, structs (structural convention programming) offer a powerful way to create custom data structures that are compact, efficient, and optimized for binary data manipulation. They are essential for working with binary data, interfacing with C libraries, and low-level system functions. Understanding Python structs can help you tackle complex problems, optimize memory usage, and improve your overall programming skills.

Prerequisites

Before diving into Python structs, make sure you have a solid understanding of the following:

  • Basic Python syntax (variables, functions, loops, conditional statements)
  • Data types in Python (int, float, str, list, tuple)
  • File I/O operations (reading and writing files)
  • Understanding binary data representation
  • Familiarity with basic C programming concepts (optional but recommended for interfacing with C libraries)

Core Concept

A Python struct is a predefined format for organized data storage. It allows you to work with binary data more efficiently by defining the order of fields in memory and their types. This can be particularly useful when interfacing with C libraries or working with low-level system functions.

To create a struct, use the struct module from Python's standard library. Here's an example of defining a simple struct called Person:

import struct

person_fmt = '32s 8i 16.4f' # Format string for Person struct: name (32 characters), age (8 integers for 4 bytes each), and float (16 decimal places)
person_size = struct.calcsize(person_fmt)

In this example, we define a Person struct with three fields: name (32 characters), age (8 integers for 4 bytes each), and a floating-point number (16 decimal places). The format string specifies the order and type of each field.

To pack a Person instance into binary data, use the struct.pack() function:

person_data = struct.pack(person_fmt, 'John Doe'.encode(), 25, 1.75)

On the other hand, to unpack binary data into a Person instance, use the struct.unpack() function:

name, age, height = struct.unpack(person_fmt, person_data)
print('Name:', name.decode(), 'Age:', age, 'Height:', height)

Struct Field Types

Python structs support various field types, including integers (i for signed, I for unsigned), floating-point numbers (f for float, d for double), characters (c), and strings (s). The number following the type specifier indicates the length of the field in bytes. For example, '32s' represents a string of 32 characters.

Struct Packing and Unpacking Examples

Here are some examples of packing and unpacking different types of data using Python structs:

Packing an integer (4 bytes)

int_data = struct.pack('i', 123)

print(int_data) # b'\x7b\x00\x00\x00'

Unpacking an integer

packed_int = b'\x7b\x00\x00\x00'

unpacked_int = struct.unpack('i', packed_int)[0]

print(unpacked_int) # 123

Packing a floating-point number (8 bytes)

float_data = struct.pack('d', 3.14159)

print(float_data) # b'\xcd\xbf\x00\x00\x00\x00\x00\x00'

Unpacking a floating-point number

packed_float = b'\xcd\xbf\x00\x00\x00\x00\x00\x00'

unpacked_float = struct.unpack('d', packed_float)[0]

print(unpacked_float) # 3.14159

Worked Example

Let's create a simple program that reads binary data containing multiple Person structs and prints their information.

  1. First, we define the format string for our Person struct and calculate its size:
import struct

person_fmt = '32s 8i 16.4f'
person_size = struct.calcsize(person_fmt)
  1. Next, we open a binary file containing our Person data and read it in chunks of person_size bytes:
with open('persons.bin', 'rb') as f:
persons = []
while True:
person_data = f.read(person_size)
if not person_data:
break
name, age, height = struct.unpack(person_fmt, person_data)
persons.append((name.decode(), age, height))
  1. Finally, we print the information for each Person in our list:
for person in persons:
print('Name:', person[0], 'Age:', person[1], 'Height:', person[2])

Common Mistakes

  1. Forgetting to encode the name string before packing: Remember that the name field is a string, so it needs to be encoded before being packed into binary data using struct.pack().
  1. Using the wrong format string: Make sure your format string matches the order and types of your struct fields. Incorrect formatting can lead to unexpected results or errors when unpacking binary data.
  1. Not handling end-of-file cases correctly: When reading binary data in chunks, always check if there's no more data left before exiting the loop. In our example, we use if not person_data: to handle this case.
  1. Misunderstanding field length and type: Be aware of the number of bytes each field occupies in memory and the appropriate type specifier for each field. For example, a single-byte character (c) should be used instead of a multi-byte string (s) when dealing with individual characters.
  1. Not accounting for byte order differences: Python's struct module uses little-endian byte order by default, but some systems might use big-endian byte order. To handle this, you can use the > or < format specifiers to explicitly specify the byte order (big-endian or little-endian).

Practice Questions

  1. Define a new struct called Book with fields for title (32 characters), author (16 characters), and publication year (4 integers). Write code to pack and unpack a Book instance.
  1. Modify the worked example to handle multiple types of structs in the same binary file. Create separate functions for reading and printing each type of struct.
  1. Write a program that reads binary data containing both Person and Book structs and prints their information separately.
  1. Explore how to use Python structs to interface with C libraries, such as the OpenCV library for image processing.

FAQ

  1. Why not use classes instead of structs?: While classes offer more flexibility, they can be less efficient when dealing with binary data or interfacing with C libraries. Structs provide a simpler and more compact solution for these scenarios.
  1. Can I define custom structs in Python 3.x?: Yes, Python 3.x supports defining custom structs using the struct module. However, Note that that Python 2.x does not support this feature natively.
  1. What happens if my binary data contains more or fewer struct instances than expected?: If your binary data contains an unexpected number of struct instances, you may encounter errors when reading the data. To avoid this, make sure your program can handle variations in the number of instances appropriately. One way to do this is by using a loop that reads and processes data until there's no more left.
  1. How can I pack multiple struct instances into one binary file?: To pack multiple struct instances into one binary file, you can simply concatenate their packed binary representations. Make sure to calculate the size of each struct instance separately and adjust the chunk size accordingly when reading from the binary file.
  1. How do I handle different byte orders between Python and C?: When interfacing with C libraries that use a different byte order, you can use the array module in Python to create an array with the correct byte order and then pack or unpack it using the struct module. For example:
import array
import struct

Create an array with big-endian byte order

big_endian_array = array.array('I', [1, 2, 3, 4])

Pack the array into binary data using little-endian format

binary_data = big_endian_array.tostring()

packed_data = struct.pack('<4i', *big_endian_array)


In this example, we create a big-endian array and then pack it into binary data using the little-endian format (indicated by '<'). The `*` operator is used to unpack the elements of the array.
Structs (Python Programming) | Python | XQA Learn