🐍 Dataclasses: Clean Data Models with @dataclass When writing object-oriented Python to store data, developers historically wrote immense amounts of repetitive boilerplate:
Defining __init__() assigning self.x = x Defining __repr__() to make printing readable Defining __eq__() so instances could be compared for equality Defining __hash__() for dictionary keys Python 3.7 introduced the standard dataclasses module (PEP 557). It automatically generates these special dunder methods using class type annotations!
The Boilerplate Heavy Way: 1 class Student :
2 def __init__ ( self , name : str , roll_no : int , course : str = "Python Mastery" ) :
3 self . name = name
4 self . roll_no = roll_no
5 self . course = course
6
7 def __repr__ ( self ) :
8 return f"Student(name= { self . name !r } , roll_no= { self . roll_no } , course= { self . course !r } )"
9
10 def __eq__ ( self , other ) :
11 if not isinstance ( other , Student ) :
12 return False
13 return ( self . name , self . roll_no , self . course ) == ( other . name , other . roll_no , other . course )
The Modern @dataclass Way: 1 from dataclasses import dataclass
2
3 @dataclass
4 class Student :
5 name : str
6 roll_no : int
7 course : str = "Python Mastery"
8
9 s1 = Student ( "Aarav Sharma" , 101 )
10 s2 = Student ( "Aarav Sharma" , 101 )
11
12 print ( s1 ) # Student(name='Aarav Sharma', roll_no=101, course='Python Mastery')
13 print ( s1 == s2 ) # True! (__eq__ generated automatically)
Just 5 lines of code replaced 18 lines of boilerplate!
Never set mutable defaults (like lists or dictionaries) directly in class attributes. Use field(default_factory=...):
1 from dataclasses import dataclass , field
2
3 @dataclass
4 class StudentBatch :
5 batch_name : str
6 students : list [ str ] = field ( default_factory = list )
7
8 morning_batch = StudentBatch ( "Morning Python Cohort" )
9 morning_batch . students . append ( "Aarav" )
10 morning_batch . students . append ( "Diya" )
11
12 print ( morning_batch )
13 # StudentBatch(batch_name='Morning Python Cohort', students=['Aarav', 'Diya'])
If you want your data structure to be read-only (immutable like a tuple) and hashable so it can be used as a dictionary key or placed inside a set, pass frozen=True:
1 from dataclasses import dataclass
2
3 @dataclass ( frozen = True )
4 class CoursePricing :
5 course_slug : str
6 tuition_fee : int
7
8 fee_tier = CoursePricing ( "python-mastery" , 4999 )
9 print ( fee_tier . tuition_fee )
10
11 # ❌ FrozenInstanceError: cannot assign to field 'tuition_fee'
12 # fee_tier.tuition_fee = 3999
If you need to validate data or compute derived fields immediately after __init__ runs, define __post_init__():
1 from dataclasses import dataclass
2
3 @dataclass
4 class Employee :
5 name : str
6 base_salary : float
7 bonus : float = 0.0
8 total_comp : float = field ( init = False )
9
10 def __post_init__ ( self ) :
11 self . total_comp = self . base_salary + self . bonus
12
13 emp = Employee ( "Er. Sumit Kumar" , 150000.0 , 25000.0 )
14 print ( f"Total Compensation: ₹ { emp . total_comp : ,.2f } " ) # ₹175,000.00
Interactive Quiz • Knowledge Check
Practice Quiz In which Python version was the dataclasses module officially introduced?
A Python 3.5
B Python 3.7
C Python 3.10
D Python 3.12
Which dunder methods does @dataclass generate by default?
A __init__, __repr__, and __eq__
B Only __str__
C Only __hash__
D __enter__ and __exit__
Why should you use field(default_factory=list) instead of students: list = [] in a dataclass?
A Python does not allow square brackets in dataclasses
B Mutable default arguments are shared across all instances, causing accidental shared state
C default_factory speeds up execution by 50%
D It is required only for numbers
What does the frozen=True parameter enforce on a dataclass?
A It compiles the class to C code
B Instances become immutable; attempting to modify an attribute raises a FrozenInstanceError
C The class cannot be inherited from
D Attributes cannot have type hints
What is the purpose of the __post_init__() method in a dataclass?
A It runs before Python creates the object
B It executes immediately after the generated __init__() completes, allowing validation and derived attribute computation
C It deletes the instance from memory
D It converts the dataclass into a JSON string
In the next lesson, we will master Object Mutability: Shallow Copy vs Deep Copy (5: Object-Oriented Programming (Intermediate)).
👉 Continue to Next Lesson: Object Mutability: Shallow Copy vs Deep Copy →