@dataclass, defaults & field(default_factory)
Data classes
Lesson 9 of 20 · 11 min · Module 3: Objects that behave
Many classes exist mainly to hold data. Writing __init__, __repr__, and __eq__ by hand for each of them is repetitive. @dataclass generates them for you.
Start this lesson →Free. No installation: you write and run the code in your browser, and it is checked automatically.
By the end, you’ll be able to…
- Define a dataclass
- Choose safe defaults
- Use generated equality and repr
The idea
Declare fields with type annotations. Fields with defaults must come after fields without. For a mutable default such as a list, use field(default_factory=list), so each object gets its own list. Methods work like in any class.
from dataclasses import dataclass, field
@dataclass
class Course:
title: str
lessons: int = 20
tags: list = field(default_factory=list)
print(Course("Python"))
01What you get for free
@dataclass writes __init__ from the fields, a readable __repr__ such as Task(title='Write', priority=3, tags=[], done=False), and __eq__ that compares field values.
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
print(Point(1, 2) == Point(1, 2))True02Mutable defaults, again
tags: list = [] would be shared between objects, the same trap as with function defaults. Python even refuses it for dataclasses; field(default_factory=list) creates a fresh list per object.
03Still a normal class
You can add methods, properties, and class variables. Use frozen=True in @dataclass(frozen=True) when objects must not change after creation.
Your turn
Task with title (str), priority (int, default 3), tags (list, a new empty list for each task), and done (bool, default False). Add complete(), which sets done to True and returns the task, and add_tag(tag), which stores the tag in lowercase only once.What the checks look for
- Task is a dataclass with the right defaults
- Each task has its own tag list
- add_tag lowercases and avoids duplicates
- complete() marks the task done and returns it; equality is automatic
Take this with you
Use @dataclass for classes that mostly hold data; it removes boilerplate and bugs.
Go a little further
Add a class method Task.from_text("Buy milk !1") that parses the priority from the text.