@dataclass
是 Python dataclasses
模块中的一个 decorator。当使用 @dataclass
装饰器时,它会自动生成一些特殊方法,包括:
_ _ init _ _
:用于初始化字段的构造函数_ _ repr _ _
:对象的字符串表示_ _ eq _ _
:对象之间的相等比较_ _ hash _ _
:使对象可用作字典键(如果值是可哈希的)
除了上述列出的方法之外,@dataclass
装饰器还有两个重要的属性。
- Order(顺序):如果为
True
(默认为False
),将生成[__lt__()](<https://docs.python.org/3/reference/datamodel.html#object.__lt__>)
、[__le__()](<https://docs.python.org/3/reference/datamodel.html#object.__le__>)
、[__gt__()](<https://docs.python.org/3/reference/datamodel.html#object.__gt__>)
和[__ge__()](<https://docs.python.org/3/reference/datamodel.html#object.__ge__>)
方法;即@dataclass(order=True)
。 - Immutability(不可变性):通过使用
frozen=True
参数,可以使字段变为不可变;即@dataclass(frozen=True)
。
简而言之,@dataclass
装饰器的主要目标是简化类的创建。
dataclass 装饰器的优势
使用 dataclass
装饰器有几个优势:
- 减少样板代码:通过自动生成常见特殊方法,减少类所需的样板代码。
- 可读性:通过使代码更简洁,集中在数据表示上,提高了代码的可读性。
- 默认值:可以直接在类定义中为属性提供默认值,减少了显式
__init__()
方法的需求。 - 不可变性:通过将
@dataclass
与frozen=True
选项结合使用,可以创建不可变的数据类,确保实例在创建后无法修改。
用法
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
在这个例子中,Person
类被注解为 @dataclass
,并声明了两个字段(name
和 age
)。__init__()
、__repr__()
、__eq__()
和 __hash__()
方法会自动生成。下面是如何使用每个生成的方法的解释:
__init__(self, ...)
**:__init__
方法会自动生成,参数对应于被注释属性。可以通过为属性提供值来创建类的实例。
person = Person('Sam', 45)
__repr__(self) -> str
:__repr__
方法返回对象的字符串表示,用于调试和记录。在打印对象或在 f-string 中使用时,将调用__repr__
方法。
person # Person(name='Sam', age=45)
__eq__(self, other) -> bool
:__eq__
方法根据属性检查两个对象是否相等。在使用等号运算符(==)
比较对象时使用。
# 用法
person1 = Person('Sam', 45)
person1
person2 = Person('Sam', 46)
person2
print(person1 == person2) # False。
__hash__(self) -> int
:__hash__
方法为对象生成哈希值,允许实例用作集合和字典中的键。当类用作字典中的键或集合中的元素时,需要这个方法。
顺序
如果包括 order=True
选项,将生成额外的顺序方法(__lt__
、__le__
、__gt__
和 __ge__
)。这些方法允许使用小于、小于或等于、大于和大于或等于运算符比较实例。如果在没有 order
的情况下对 Person
对象进行比较,将引发 TypeError
。
添加顺序后,我们可以执行比较。
order
默认为 False
,这意味着除非显式启用,否则不会生成比较方法。比较基于字段值,而不是对象标识。
不可变性
使用 frozen=True
属性可以使 @dataclass
不可变;默认为 False
。
在上面的代码中,我们能够重新分配值给 Person
的 name
字段。添加 frozen=True
后,将引发异常,不允许重新分配。
注意性能影响:frozen=True
会增加轻微的开销,因为需要额外检查不可变性。
总结
使用 dataclasses
模块,我们可以在类定义中为字段分配默认值。
默认值可以是任何数据类型,包括其他数据类或可变对象。它们在定义类时仅计算一次,而不是每次创建实例时。