Binary Data with struct
The struct module converts between Python values and compact C-style bytes, letting you pack numbers into binary and unpack raw bytes from files, packets, and devices.
Learn Binary Data with struct in our free Python course — an interactive lesson with runnable examples, a practice exercise and a quick reference.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
When you need to read a binary file header or speak a wire protocol, struct is the precise, byte-accurate tool — a tiny format string describes exactly how the bytes are laid out.
struct.pack(fmt, *values) writes values into a bytes object; struct.unpack(fmt, data) reads them back as a tuple. The format string describes the layout — here means two shorts and a long, all big-endian:
The first character of a format sets byte order . The same number 1 packs to different bytes depending on endianness, which is why you must always be explicit when parsing a real format:
Network protocols and many file formats use big-endian ( or ! ). Pick one and stick with it across pack and unpack.
Real binary formats start with a fixed header : a magic signature, a version, and some counts. struct.calcsize(fmt) tells you how many bytes that header occupies, so you know exactly how much to read:
Fill in each ___ so the format string is big-endian and the round-trip prints the original values. (Hint: H = unsigned short, I = unsigned int.)
A device emits a stream of fixed-size records: an id ( H ) and a reading ( f ), big-endian. Pack three of them, then loop through the bytes calcsize at a time to unpack each record.
Lesson complete — you speak binary now!
You can pack values into bytes and unpack them back, read format characters like i , h , f , and s , control endianness with , use calcsize to measure layouts, and walk a binary stream record by record.
🚀 Up next: text wrapping & formatting — make long text readable with the textwrap module.
Practice quiz
What does the struct module do?
- Defines C-style structs as Python classes
- Compresses Python objects to disk
- Converts between Python values and C-style packed bytes
- Parses JSON into objects
Answer: Converts between Python values and C-style packed bytes. struct packs Python values into compact bytes and unpacks bytes back into values using a format string.
What does struct.unpack always return?
- A tuple, even for one value
- A single value
- A list
- A dictionary
Answer: A tuple, even for one value. unpack returns a tuple even for a single value: struct.unpack('>i', data) gives (5,), so index [0] or unpack it.
What does the '<' prefix mean in a format string?
- Big-endian
- Network byte order
- Native with padding
- Little-endian
Answer: Little-endian. '<' is little-endian (least significant byte first); '>' and '!' are big-endian, '=' is native order.
Which prefix means network byte order?
- <
- !
- =
- @
Answer: !. '!' is network byte order, which is the same as big-endian ('>').
What is the size of the format '>4sHI' according to struct.calcsize?
- 10
- 7
- 8
- 12
Answer: 10. 4s (4) + H (2) + I (4) = 10 bytes, since the explicit byte-order prefix removes padding.
What does the 'f' format character represent?
- A 2-byte short
- An 8-byte double
- A 4-byte float
- A flag bit
Answer: A 4-byte float. 'f' is a 4-byte float; 'd' is an 8-byte double, 'h' a 2-byte short, 'i' a 4-byte int.
Why do you get bytes back instead of a str from an 's' format?
- struct only works on numbers
- struct works at the byte level, so you decode text yourself
- It is a bug in struct
- The encoding was wrong
Answer: struct works at the byte level, so you decode text yourself. The 's' code yields a bytes object; decode it yourself with .decode('utf-8') or 'ascii' when you know the encoding.
What does struct.pack('>H', 258) produce?
- b'\x02\x01'
- b'\x00\x00'
- b'258'
- b'\x01\x02'
Answer: b'\x01\x02'. 258 is 0x0102; big-endian writes the most significant byte first, giving b'\x01\x02'.
What does struct.unpack('>i', b'\x00\x01') raise?
- Nothing — it returns (1,)
- A struct.error, because the buffer must be 4 bytes
- A TypeError
- A UnicodeDecodeError
Answer: A struct.error, because the buffer must be 4 bytes. The 'i' format needs exactly 4 bytes; a 2-byte buffer raises struct.error. Match the buffer to calcsize(fmt).
Why should you always include a byte-order prefix in a format string?
- It makes packing faster
- It is required syntax
- Without one, native order plus padding can give surprising sizes
- It enables compression
Answer: Without one, native order plus padding can give surprising sizes. No prefix means native byte order with alignment padding, so sizes vary by platform; a prefix gives exact, portable layouts.