Introduction
Dataclasses provide a way to define classes primarily to store data. Using post_init and field validators, we can add validation and computed fields.
Basic Dataclass
from dataclasses import dataclass, field
@dataclass
class Point:
x: float
y: float
def distance_from_origin(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
p = Point(3, 4)
print(p.distance_from_origin()) # 5.0
Post Init Validation
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
def __post_init__(self):
if self.age < 0:
raise ValueError("Age cannot be negative")
if not self.name:
raise ValueError("Name cannot be empty")
person = Person("Alice", 30)
Field Validators
from dataclasses import dataclass, field
from typing import List
@dataclass
class Team:
name: str
members: List[str] = field(default_factory=list)
def add_member(self, member: str):
if member not in self.members:
self.members.append(member)
Field with Validator
from dataclasses import dataclass, field
from typing import Any
def validate_positive(instance, field_obj, value):
if value < 0:
raise ValueError(f"{field_obj.name} must be positive")
return value
@dataclass
class Product:
name: str
price: float = field(default=0, metadata={"validator": validate_positive})
quantity: int = 0
Complex Validation
from dataclasses import dataclass, field
from datetime import datetime
@dataclass
class Event:
name: str
start_date: datetime
end_date: datetime
def __post_init__(self):
if self.end_date <= self.start_date:
raise ValueError("End date must be after start date")
@property
def duration_days(self):
return (self.end_date - self.start_date).days
Practice Problems
- Validate email format in dataclass
- Create post-init validation for date ranges
- Use field default_factory for mutable defaults
- Implement computed properties
- Build nested dataclass with validation