patternpythonnoneModerate
Python dataclasses vs attrs vs Pydantic: When to Use Each
Viewed 0 times
Python 3.10+, Pydantic v2
dataclassesattrspydanticdata classvalidationserialization
Error Messages
Problem
Python has multiple data class libraries. Choosing the wrong one for the use case leads to missing validation, performance issues, or excessive boilerplate.
Solution
Choose based on your primary need: stdlib simplicity, performance, or validation.
# dataclasses — stdlib, simple, no validation
from dataclasses import dataclass, field
from typing import List
@dataclass
class User:
name: str
email: str
tags: List[str] = field(default_factory=list)
# No runtime validation — name could be an int
# attrs — performance, validators, converters
import attr
@attr.s(auto_attribs=True, slots=True)
class User:
name: str = attr.ib(validator=attr.validators.instance_of(str))
email: str = attr.ib()
tags: list = attr.ib(factory=list)
# 2-5x faster than dataclasses for large-scale use
# Pydantic v2 — validation + serialization (FastAPI standard)
from pydantic import BaseModel, EmailStr, field_validator
class User(BaseModel):
name: str
email: EmailStr # Validates format
tags: list[str] = []
@field_validator('name')
@classmethod
def name_not_empty(cls, v: str) -> str:
if not v.strip():
raise ValueError('Name cannot be empty')
return v.strip()
user = User(name='Alice', email='alice@example.com')
user.model_dump() # {'name': 'Alice', 'email': 'alice@example.com', 'tags': []}Why
dataclasses are built-in but have no validation. attrs has validators and is faster (optional slots). Pydantic v2 (Rust core) has runtime type coercion and validation, essential for API boundaries.
Gotchas
- Pydantic v2 changed from .dict() to .model_dump() and .json() to .model_dump_json() — v1 code needs migration.
- dataclasses with mutable defaults require field(default_factory=...) — using [] directly raises an error.
- attrs slots=True means you can't add arbitrary attributes — use slots only for stable data classes.
Revisions (0)
No revisions yet.