Python dataclass 实用指南:少写样板代码的 5 个技巧
【摘要】 Python dataclass 实用指南:少写样板代码的 5 个技巧写 Python 时,只负责存数据的类很常见。手写 __init__、__repr__、__eq__ 既啰嗦又容易漏。标准库的 dataclasses(Python 3.7+)可以自动生成这些方法。下面用可运行的例子讲 5 个常用技巧,示例在 Python 3.10+ 下验证过。 1. 基本用法与可变默认值from da...
Python dataclass 实用指南:少写样板代码的 5 个技巧
写 Python 时,只负责存数据的类很常见。手写 __init__、__repr__、__eq__ 既啰嗦又容易漏。标准库的 dataclasses(Python 3.7+)可以自动生成这些方法。下面用可运行的例子讲 5 个常用技巧,示例在 Python 3.10+ 下验证过。
1. 基本用法与可变默认值
from dataclasses import dataclass, field, asdict
@dataclass
class User:
name: str
age: int = 0
tags: list = field(default_factory=list)
u = User("小明", 20)
u.tags.append("python")
print(u) # User(name='小明', age=20, tags=['python'])
print(asdict(u)) # {'name': '小明', 'age': 20, 'tags': ['python']}
注意:列表、字典这类可变默认值不能直接写 tags: list = [],dataclass 会直接抛出 ValueError。必须用 field(default_factory=list),这样每个实例都有独立的列表。
2. frozen=True:不可变且可哈希
@dataclass(frozen=True, order=True)
class Point:
x: int
y: int
a, b = Point(1, 2), Point(1, 3)
print(a < b) # True,order=True 按字段顺序比较
try:
a.x = 5
except Exception as e:
print(type(e).__name__) # FrozenInstanceError
print({a: "ok"}[Point(1, 2)]) # ok,可作字典键
frozen=True 让实例创建后不能修改,同时会生成 __hash__,所以可以放进集合或当字典键。适合坐标、配置项、缓存键。
3. post_init:派生字段与校验
@dataclass
class Order:
price: float
qty: int
total: float = field(init=False)
def __post_init__(self):
if self.qty < 0:
raise ValueError("qty 不能为负")
self.total = self.price * self.qty
print(Order(2.5, 4)) # Order(price=2.5, qty=4, total=10.0)
field(init=False) 表示该字段不出现在构造参数里,由 __post_init__ 在初始化后计算。校验逻辑也放在这里。
4. slots=True:省内存、防拼错属性
Python 3.10 起可以写 @dataclass(slots=True):
@dataclass(slots=True)
class S:
a: int
print(hasattr(S(1), "__dict__")) # False
实例不再有 __dict__,创建大量对象时更省内存,给不存在的属性赋值会直接报错,能提前发现拼写错误。
5. 常见陷阱
- 有默认值的字段必须放在没有默认值的字段后面,否则报 TypeError。需要打破限制时可用
kw_only=True(3.10+)。 asdict会递归拷贝嵌套的 dataclass、列表和字典,数据量大时有开销。- 默认的
__eq__只在两个对象类型相同时才比较字段;eq=True且非 frozen 时__hash__会被置为 None,即不可哈希。 - 需要运行时类型校验时,dataclass 不会帮你做,类型注解只是提示,这时可以考虑 pydantic。
小结
dataclass 适合承载数据的轻量类:默认值用 default_factory,需要不可变就加 frozen=True,派生字段与校验放进 __post_init__,对象很多时考虑 slots=True。几行代码就能替代几十行样板,也更不容易出错。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)