Of course! The term "struct type" in Python can refer to a few different things, as Python doesn't have a single built-in struct type like C or C++. Instead, it offers several excellent ways to create structured data.

Here’s a comprehensive guide covering the most common and modern approaches, from simple to more advanced.
Summary: Which One Should I Use?
| Method | Best For | Pros | Cons |
|---|---|---|---|
dataclasses |
Most use cases. Default modern choice. | Clean, readable, type-hinted, less boilerplate. | Not as performant as NamedTuple for read-heavy, immutable data. |
NamedTuple |
Immutable, read-heavy data. Performance-critical apps. | Very fast, memory-efficient, acts like a tuple. | Immutable (can't change values), slightly more verbose setup. |
typing.NamedTuple |
A modern, type-hinted version of NamedTuple. |
Combines speed of NamedTuple with type hints. |
Still immutable. |
dict (Dictionary) |
Simple, unstructured key-value pairs. | Built-in, flexible, fast. | No type safety, typos in keys cause silent bugs. |
SimpleNamespace |
Simple, object-like access without full class syntax. | Easy to create and use. | No type hints, no validation. |
Struct (from ctypes) |
Interfacing with C code or binary data. | Direct mapping to C structs. | Overkill for most Python-only applications. |
The Modern Standard: dataclasses (Python 3.7+)
This is the recommended approach for most new Python code. It provides a decorator and functions to add special methods like __init__, __repr__, and __eq__ to your classes with minimal boilerplate.
How to use it:
from dataclasses import dataclass
@dataclass
class Product:
"""A simple data structure for a product."""
name: str
price: float
stock_quantity: int = 0 # A default value
# --- Usage ---
# 1. Create an instance (like a regular class)
laptop = Product(name="Laptop Pro", price=1200.50, stock_quantity=50)
# 2. Access attributes like an object
print(f"Product Name: {laptop.name}")
print(f"Price: ${laptop.price}")
print(f"Stock: {laptop.stock_quantity}")
# 3. It automatically creates a nice __repr__ for debugging
print(laptop)
# Output: Product(name='Laptop Pro', price=1200.5, stock_quantity=50)
# 4. It automatically creates an __eq__ for comparison
phone = Product(name="Smartphone", price=800.0, stock_quantity=100)
print(laptop == phone) # Output: False
# 5. You can modify attributes (it's mutable)
laptop.price = 1150.00
print(f"New Price: ${laptop.price}")
Key Features:

- Type Hints: Encourages and supports type hints, which are great for static analysis and IDE autocompletion.
- Mutable: Instances can be modified after creation.
- Less Boilerplate: Dramatically reduces the amount of "dunder" (double underscore) code you have to write.
- Fields with Defaults: Easy to set default values for fields.
The Classic High-Performance Choice: collections.namedtuple
Before dataclasses, this was the go-to for creating simple, immutable data structures. It's essentially a tuple with named fields.
How to use it:
from collections import namedtuple
# 1. Define the "struct" by creating a new type
# Syntax: TypeName = namedtuple('TypeName', ['field1', 'field2', ...])
Point = namedtuple('Point', ['x', 'y'])
# 2. Create an instance
p1 = Point(x=10, y=20)
p2 = Point(15, 25) # Positional arguments also work
# 3. Access attributes by name
print(f"p1.x: {p1.x}")
print(f"p1.y: {p1.y}")
# 4. It's still a tuple, so you can access by index
print(f"p1[0]: {p1[0]}")
# 5. It has a nice __repr__
print(p1)
# Output: Point(x=10, y=20)
# 6. It's IMMUTABLE. This will raise an error:
# p1.x = 30 # AttributeError: can't set attribute
# 7. It's hashable, so you can use it as a dictionary key or in a set
points_set = {p1, p2}
print(points_set)
Key Features:
- Immutable: Once created, a
NamedTuplecannot be changed. This makes it safe to use as dictionary keys or in sets. - Memory Efficient: It's more memory-efficient than a regular class instance.
- Fast: Attribute access is very fast, often faster than a regular class.
- No Type Hints (in the standard library version): The fields are just strings, so you don't get type checking.
The Modern High-Performance Choice: typing.NamedTuple (Python 3.6+)
This is a hybrid that combines the performance and immutability of collections.namedtuple with the type-hinting capabilities of dataclasses.

How to use it:
from typing import NamedTuple
# 1. Define the struct using a class-like syntax
class User(NamedTuple):
user_id: int
username: str
is_active: bool = True # Defaults are supported
# 2. Create an instance
u1 = User(user_id=101, username="alice")
u2 = User(102, "bob", False)
# 3. Access attributes by name
print(u1.username)
print(u2.is_active)
# 4. It's immutable and hashable, just like the classic version
# u1.user_id = 103 # Raises AttributeError
# 5. It has type hints for better IDE support and static analysis
# mypy or other linters can catch type errors here
The Simple Way: dict (Dictionary)
For very simple cases, a dictionary is the most straightforward built-in solution.
# Create a dictionary
person = {
"name": "Charlie",
"age": 35,
"city": "New York"
}
# Access values
print(person["name"])
# Modify values
person["age"] = 36
# Add new keys
person["email"] = "charlie@example.com"
Downside: There's no structure. If you misspell a key, you get a KeyError or create a new one accidentally. There are no type hints.
The Object-Like Shortcut: types.SimpleNamespace
This is a handy utility if you just want an object that you can assign attributes to without writing a full class.
from types import SimpleNamespace # Create a namespace object directly ns = SimpleNamespace(name="David", job="Engineer", location="London") # Access attributes like an object print(ns.name) print(ns.location) # Modify attributes ns.job = "Senior Engineer" print(ns.job)
Downside: No type hints, no validation, and no real structure. It's just a flexible bag of attributes.
For C Interfacing: struct from ctypes
This is a very specialized tool for interacting with C libraries or binary data files. It maps Python types directly to C struct definitions.
How to use it:
from ctypes import Structure, c_int, c_char_p
# 1. Define a C-style struct
class Employee(Structure):
_fields_ = [
("id", c_int),
("name", c_char_p),
("age", c_int)
]
# 2. Create an instance
# Note: For c_char_p, you need to encode the string
e = Employee(id=123, name=b"Frank", age=45)
# 3. Access fields by name
print(e.name) # Output: b'Frank' (bytes object)
print(e.age)
Use Case: Reading binary data from a file that was written by a C program, or calling functions in a shared C library that expect a struct as an argument. This is not for general data modeling in Python.
