Python struct Module

Learn how to use the Python struct module to pack and unpack binary data. See examples for struct.pack(), struct.unpack(), struct.calcsize(), byte order, format strings, pack_into(), unpack_from(), and common errors.

Published

Updated

Read time 7 min read

Reviewed byDeepak Prasad

Python struct Module

The struct module packs Python values into bytes and unpacks bytes back into Python values. It is useful for binary files, network packets, C-compatible records, device data, and any format where byte layout matters.

Tested on: Python 3.13.3; kernel 6.14.0-37-generic.


Quick answer: pack and unpack binary data

Use struct.pack() to convert values to bytes. Use struct.unpack() to convert bytes back to values. Use struct.calcsize() to learn how many bytes a format string needs.

python
import struct

data = struct.pack("if", 42, 3.14)
print(data)
print(struct.unpack("if", data))
print(struct.calcsize("if"))
Output

The first line prints a bytes object. The second returns a tuple such as (42, 3.14). The third prints the byte size of the format, which is 8 on a typical 64-bit Linux system for "if".


Python struct quick reference

Task Use
Pack values into bytes struct.pack(format, values...)
Unpack bytes into values struct.unpack(format, data)
Get byte size of format struct.calcsize(format)
Pack into existing buffer struct.pack_into(format, buffer, offset, values...)
Unpack from buffer offset struct.unpack_from(format, buffer, offset=0)
Unpack repeated records struct.iter_unpack(format, buffer)
Reuse compiled format struct.Struct(format)
Little-endian data "<" prefix
Big-endian data ">" prefix
Network byte order "!" prefix

What is the Python struct module?

struct converts between Python values and binary bytes with a fixed layout. It is not the same as a Python class or dataclass. You define the layout with a format string, and Python reads or writes the exact byte pattern.

python
import struct

sensor_id = 7
temperature = 23.5

data = struct.pack("<if", sensor_id, temperature)
values = struct.unpack("<if", data)

print(data)
print(values)
Output

The first line prints raw bytes such as b'\x07\x00\x00\x00\x00\x00\xbc\x41'. The second prints a tuple like (7, 23.5) with the original values restored.

Common uses include binary file headers, network packets, C-compatible records, sensor or device payloads, and protocol parsing where each field has a known size and order. Pair with Python datetime when timestamps in binary layouts need conversion.


Why use struct in Python?

Normal Python strings hold text. Binary formats need exact byte sizes, byte order, and field boundaries. struct lets you describe that layout in one format string and convert values reliably.

When you read a 4-byte integer from a file or socket, you usually need struct (or a similar binary parser), not string methods.


Python struct format strings

A format string describes how values are stored in bytes. Each character is a type code. Optional prefix characters control byte order, size, and alignment.

Examples:

  • i — signed integer
  • f — float
  • d — double
  • s — bytes (fixed-width byte string)
  • c — one byte character

The Python struct documentation lists every format character and prefix option.


Common struct format characters

Format Meaning Python value
b signed char int
B unsigned char int
h short int
H unsigned short int
i int int
I unsigned int int
q long long int
Q unsigned long long int
f float float
d double float
? bool bool
c char bytes of length 1
s char[] bytes

Repeat a character for multiple fields. "iii" packs three integers. "if" packs one integer followed by one float.


Byte order, size, and alignment

If you omit a prefix, struct uses native mode. Native packing depends on your platform and compiler, which is fine for in-process buffers but risky for files and network data.

For external binary formats, be explicit:

  • < — little-endian
  • > — big-endian
  • ! — network byte order (big-endian)
python
import struct

print(struct.pack(">i", 1))
print(struct.pack("<i", 1))
print(struct.pack("!i", 1))
Output

On a typical little-endian Linux host, ">i" and "!i" produce four bytes with the most significant byte first. "<i" reverses the byte order within the 4-byte integer.


struct.pack() example

struct.pack() returns a bytes object. The number of values must match the format string exactly.

python
import struct

print(struct.pack("i", 42))
print(struct.pack("if", 1, 2.5))
print(struct.pack(">ii", 10, 20))
Output

Each call returns bytes. Passing the wrong type, such as a string where an integer is required, raises struct.error.


struct.unpack() example

struct.unpack() converts bytes back into Python values. It always returns a tuple, even for a single value. The buffer size must match struct.calcsize(format).

python
import struct

data = struct.pack("iii", 1, 2, 3)
print(struct.unpack("iii", data))
print(type(struct.unpack("i", struct.pack("i", 7))))
Output

The first unpack returns (1, 2, 3). The second returns a one-item tuple. If the byte length does not match the format, unpack() raises struct.error.


struct.calcsize() example

struct.calcsize() returns how many bytes a format string requires. Use it before reading fixed-size chunks from a file or slicing a buffer.

python
import struct

print(struct.calcsize("i"))
print(struct.calcsize("iii"))
print(struct.calcsize("if"))
Output

For three native integers, calcsize("iii") is typically 12 on a 64-bit Linux system. Always call calcsize() for the exact format you plan to read or write.


pack() and unpack() together

The clearest beginner workflow is a round trip: pack Python values, then unpack the same bytes with the same format.

python
import struct

fmt = "<if"
values = (100, 3.14)

packed = struct.pack(fmt, *values)
restored = struct.unpack(fmt, packed)

print(packed)
print(restored)
Output

You should see bytes on the first line and a tuple matching the original values on the second. The explicit "<" prefix keeps the layout portable across platforms.


Read binary data from a file using struct

Open the file in binary mode ("rb"), read exactly calcsize(format) bytes, then unpack.

python
import struct
from pathlib import Path

path = Path("record.bin")
fmt = "<if"

raw = path.read_bytes()
if len(raw) != struct.calcsize(fmt):
    raise ValueError("unexpected record size")

record_id, value = struct.unpack(fmt, raw)
print(record_id, value)

This pattern fits file headers and fixed-width records. For text file patterns, see Python write to file.


Write binary data to a file using struct

Pack values first, then write the bytes. This is binary data, not text, so use "wb" or "ab".

python
import struct
from pathlib import Path

path = Path("record.bin")
fmt = "<if"

path.write_bytes(struct.pack(fmt, 7, 1.5))

The file contains raw bytes. Opening it in a text editor will not show readable text.


struct.pack_into() example

struct.pack_into() writes packed bytes into an existing writable buffer at an offset. A bytearray is the simplest buffer for beginners.

python
import struct

buf = bytearray(8)
struct.pack_into("ii", buf, 0, 10, 20)

print(bytes(buf))
Output

The buffer now holds two native integers. You can also pack at a non-zero offset when the buffer holds a header plus payload.


struct.unpack_from() example

unpack_from() reads from a buffer starting at an offset. The correct name is unpack_from(), not unpack_form(). Use it when data has a header followed by fields.

python
import struct

header = struct.pack("H", 1)
body = struct.pack("ii", 3, 4)
blob = header + body

offset = struct.calcsize("H")
print(struct.unpack_from("ii", blob, offset))
Output

The tuple (3, 4) comes from the body after the 2-byte unsigned short header. The buffer must contain enough bytes from the offset for the full format.


struct.iter_unpack() for repeated records

Use iter_unpack() when a buffer contains many records with the same format. The buffer size must be a multiple of the record size.

python
import struct

records = struct.pack("ii", 1, 2) + struct.pack("ii", 3, 4)

for item in struct.iter_unpack("ii", records):
    print(item)
Output

Each iteration yields one tuple. This is useful for binary tables or streams of equal-sized records.


struct.Struct() for reusable formats

When you use the same format many times, compile it once with struct.Struct(format).

python
import struct

record = struct.Struct("<if")

packed = record.pack(5, 2.5)
print(packed)
print(record.unpack(packed))
print(record.size)
Output

A Struct object exposes pack(), unpack(), pack_into(), unpack_from(), iter_unpack(), and size. Compiling once avoids repeating the format string and can be slightly more efficient in tight loops.


Common struct errors

python
import struct

try:
    struct.pack("i", "not-an-int")
except struct.error as exc:
    print("wrong type:", exc)

try:
    struct.unpack("i", b"\x00\x00")
except struct.error as exc:
    print("wrong size:", exc)

try:
    struct.pack("b", 300)
except struct.error as exc:
    print("out of range:", exc)
Output

Typical causes include the wrong number of values, the wrong Python type for a format character, a byte buffer that is too short for unpack(), an integer outside the range of the chosen format, and confusing str with bytes for c or s fields.


Common mistakes with Python struct

  • Thinking struct creates Python objects like C structs.
  • Forgetting that pack() returns bytes, not a string.
  • Passing normal str values where bytes are required for c or s.
  • Calling unpack() with the wrong byte length.
  • Forgetting that unpack() always returns a tuple.
  • Skipping calcsize() before reading fixed-size records from files.
  • Relying on native byte order for file or network formats.
  • Misspelling unpack_from() as unpack_form().
  • Using ctypes buffers when a simple bytearray is enough for pack_into().
  • Not decoding or stripping fixed-width s fields after unpacking.

Summary

The struct module handles binary data with fixed layouts. pack() converts Python values to bytes. unpack() converts bytes to Python values. calcsize() tells you how many bytes a format requires. Use explicit byte-order prefixes for files and network data. For headers, offsets, repeated records, or hot loops, use pack_into(), unpack_from(), iter_unpack(), or a compiled Struct object.


References


Frequently Asked Questions

1. What does the Python struct module do?

struct converts Python values to bytes with pack() and converts bytes back to Python values with unpack(). It is for fixed-layout binary data, not for general Python objects.

2. What is the difference between struct.pack() and struct.unpack()?

pack() takes Python values and returns a bytes object. unpack() takes bytes and returns a tuple of Python values in the order defined by the format string.

3. What does struct.calcsize() do?

calcsize() returns how many bytes a format string requires. Use it before reading fixed-size records from a binary file or validating buffer length.

4. What is a struct format string?

A format string describes binary layout with type characters such as i for int and f for float, plus optional prefix characters for byte order and alignment.

5. When should you use < or > in a struct format string?

Use < for little-endian and > for big-endian when reading files, network packets, or any data from outside your process. Native mode without a prefix depends on the platform.

6. What is the difference between unpack() and unpack_from()?

unpack() reads from the start of a buffer. unpack_from() starts at a given offset, which is useful when a buffer has a header followed by records.
Bashir Alam

Data Analyst and Machine Learning Engineer

Computer Science graduate from the University of Central Asia, currently employed as a full-time Machine Learning Engineer at uExel. His expertise lies in OCR, text extraction, data preprocessing, and …