Python Basics: Keeping Related Values in a Dataclass
A task has several related values: a name, a retry limit, and labels. A dataclass gives those values named fields without writing a constructor yourself.
Use Python 3.12 or newer on Linux. These independent examples work in memory.
Define a small record
Save as demo_dataclasses_1.py:
from dataclasses import dataclass
@dataclass
class Task:
name: str
retries: int = 2
task = Task("backup")
print(task)
print("Retries:", task.retries)
print("Same values:", task == Task("backup", 2))Run it from the directory where you saved it:
python3 demo_dataclasses_1.pyOutput:
Task(name='backup', retries=2)
Retries: 2
Same values: TrueThe decorator generates initialization, a readable representation, and equality based on fields. Put required fields before fields with defaults. Type annotations describe expected values; they do not validate them at runtime.
Give each record its own list
Save as demo_dataclasses_2.py:
from dataclasses import dataclass, field
@dataclass
class Task:
name: str
labels: list[str] = field(default_factory=list)
first = Task("backup")
second = Task("report")
first.labels.append("nightly")
print(first)
print(second)
print("Shared list:", first.labels is second.labels)Run it from the directory where you saved it:
python3 demo_dataclasses_2.pyOutput:
Task(name='backup', labels=['nightly'])
Task(name='report', labels=[])
Shared list: FalsePass list, not list(), to default_factory. Each instance gets a fresh list. A mutable field default such as labels: list[str] = [] is rejected.
Validate at construction
Save as demo_dataclasses_3.py:
from dataclasses import dataclass
@dataclass
class Task:
name: str
retries: int = 2
def __post_init__(self):
if type(self.retries) is not int or self.retries < 0:
raise ValueError("retries must be a nonnegative integer")
for retries in (0, -1, "2", True):
try:
print(Task("backup", retries))
except ValueError as error:
print(error)Run it from the directory where you saved it:
python3 demo_dataclasses_3.pyOutput:
Task(name='backup', retries=0)
retries must be a nonnegative integer
retries must be a nonnegative integer
retries must be a nonnegative integerThe generated constructor calls __post_init__(). This check deliberately rejects booleans, which are integer subclasses. It validates only retries during construction; later assignments remain possible and need their own checks.
References
Acknowledgements
This post was created with assistance from AI.