@dataclass装饰器是Python 3.7引入的工具之一,用于在创建简单数据存储类时减少模板代码。借助类型注解,Python会自动生成__init__,__repr__,__eq__等方法。
问题背景:
在引入dataclass之前,开发人员手动编写模板类,实现构造函数、比较方法、repr,之后往往转向命名元组或attrs等库。引入@dataclass标准化并简化了这个过程。
问题:
模板代码(boilerplate)、构造函数和比较方法的重复代码常常导致错误,并使大型应用程序的维护变得复杂。
解决方案:
使用类型注解和特殊的@dataclass装饰器,可以自动生成类中的所有所需方法。
代码示例:
from dataclasses import dataclass @dataclass class Point: x: int y: int p1 = Point(10, 20) p2 = Point(10, 20) print(p1 == p2) # True,自动生成__eq__ print(p1) # Point(x=10, y=20),自动生成__repr__
关键特点:
@dataclass是否改变了继承的行为(继承时的特征)?
是的。在继承dataclass类时需特别注意:基类的字段在子类字段之前,构造函数/参数顺序发生冲突时可能出现错误。如果基类和子类的不同字段同名,则后者会覆盖前者。
在dataclass中可以为字段使用可变的默认值吗?
不可以,不能直接将这些对象(例如列表)作为默认值使用——必须使用field(default_factory=list)。否则,所有类实例将共享同一个集合。
示例:
from dataclasses import dataclass, field @dataclass class User: values: list = field(default_factory=list)
@dataclass在任何场景下是否都很快?它适合优雅地存储大量数据吗?
不行。dataclass并不是内存优化的最佳选择。对于存储数百万个对象,最好使用__slots__、namedtuple或特殊结构——dataclass会增加附加字段,无法像插槽那样节省内存。可以组合使用,通过传递参数slots=True(Python 3.10+),或手动使用插槽。
@dataclass class Cart: items: list = [] # 错误! c1 = Cart() c2 = Cart() c1.items.append("a") print(c2.items) # ['a'] — 所有Cart共享一个列表
优点:
缺点:
from dataclasses import dataclass, field @dataclass class Cart: items: list = field(default_factory=list) c1 = Cart() c2 = Cart() c1.items.append("a") print(c2.items) # []
优点:
缺点:
field(default_factory=...)(这需要单独学习)。