Dataclasses & Typing
Overview
Dataclasses generate boilerplate code for data-storage classes automatically. Type annotations support static analysis check lookups.
Learning Objectives
- Define dataclasses using @dataclass.
- Use type hints to document expected variable types.
- Create immutable data classes using frozen=True.
Concept Explanation
Dataclasses (introduced in PEP 557) generate standard methods (like __init__, __repr__, and __eq__) automatically based on class variable type annotations. Frozen dataclasses (frozen=True) are read-only and hashable, making them suitable for dictionary keys.
Code Examples
Example 1 — Basics
This example introduces the fundamental syntax and concepts.
from dataclasses import dataclass
@dataclass
class Coord:
x: int
y: int
Example 2 — Everyday Usage
This example demonstrates a realistic scenario handling business parameters.
from dataclasses import dataclass
@dataclass(frozen=True) # Frozen instances are immutable
class ServerConfig:
host: str
port: int = 80
config = ServerConfig('127.0.0.1')
print(config)
# config.port = 8080 raises FrozenInstanceError
Example 3 — Advanced Example
This example shows clean, production-grade code structure following senior development standards.
from dataclasses import dataclass, field
from typing import List
@dataclass
class WorkBatch:
batch_id: int
# Use default_factory to create unique list lists for every instance
logs: List[str] = field(default_factory=list)
b1 = WorkBatch(1)
b1.logs.append('Task start')
print(b1)
Visual Flow
The following execution flow represents the step-by-step evaluation inside the interpreter:
Class variable definitions → Parse decorator metadata → Generate dunder methods code → Instantiate instances
Common Mistakes
Review these common pitfalls when working with this topic:
- Declaring mutable defaults directly (e.g. logs: list = []) instead of using default_factory, which raises a ValueError.
- Expecting type annotations to enforce checks at runtime (type hints are not enforced by Python at runtime).
- Declaring non-default fields after default fields, raising a TypeError.
- Mutating attributes inside frozen=True dataclasses.
Best Practices
Enforce these Pythonic best practices in your codebase:
class Point:
def __init__(self, x: int, y: int):
self.x = x
self.y = y # Verbose constructor boilerplate
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int # Generated initializer automatically
Quick Revision
Use these key summaries for last-minute revision:
- @dataclass decorator reduces boilerplate.
- Automatically generates repr and eq.
- Type hints are required for fields.
- Use frozen=True for immutability.
- Use default_factory for mutable defaults.
- Type annotations are not enforced at runtime.