dataclasses
问题
@dataclass 装饰器怎么用?和 Pydantic 有什么区别?
答案
基础用法
from dataclasses import dataclass, field
@dataclass
class User:
name: str
age: int
email: str = "" # 默认值
tags: list[str] = field(default_factory=list) # 可变默认值
def __post_init__(self):
"""初始化后的处理"""
self.name = self.name.strip()
user = User("Alice", 30)
print(user) # User(name='Alice', age=30, email='', tags=[])
print(user == User("Alice", 30)) # True(自动生成 __eq__)
高级选项
@dataclass(frozen=True) # 不可变(生成 __hash__)
class Point:
x: float
y: float
@dataclass(slots=True) # 3.10+,使用 __slots__ 节省内存
class Config:
host: str
port: int
@dataclass(order=True) # 自动生成比较方法
class Version:
major: int
minor: int
patch: int
dataclass vs Pydantic vs namedtuple
| 特性 | dataclass | Pydantic | namedtuple |
|---|---|---|---|
| 运行时验证 | ❌ | ✅ | ❌ |
| 可变性 | 默认可变 | 默认不可变(v2) | 不可变 |
| 序列化 | 需手动 | 内置 .model_dump() | _asdict() |
| 性能 | 最快 | 较快(v2 Rust核心) | 最快 |
| 适用场景 | 内部数据结构 | API 输入/输出验证 | 简单不可变记录 |
常见面试问题
Q1: 为什么不用 field(default=[]) 而要用 field(default_factory=list)?
答案:
与函数默认参数陷阱相同:可变默认值会被所有实例共享。default_factory 确保每次创建实例时调用 list() 生成新列表。