@dataclass(frozen=True)
示例(Python 3.7)
@dataclass
已经在 https://dev59.com/Q2445IYBdhLWcg3wXZEy#69313714 中提到过,但这里有一个示例。
这个很棒的新功能,除了其他好处之外,还会自动为您定义一个 __hash__
和 __eq__
方法,使其像通常在字典和集合中一样正常工作:
dataclass_cheat.py
from dataclasses import dataclass, FrozenInstanceError
@dataclass(frozen=True)
class MyClass1:
n: int
s: str
@dataclass(frozen=True)
class MyClass2:
n: int
my_class_1: MyClass1
d = {}
d[MyClass1(n=1, s='a')] = 1
d[MyClass1(n=2, s='a')] = 2
d[MyClass1(n=2, s='b')] = 3
d[MyClass2(n=1, my_class_1=MyClass1(n=1, s='a'))] = 4
d[MyClass2(n=2, my_class_1=MyClass1(n=1, s='a'))] = 5
d[MyClass2(n=2, my_class_1=MyClass1(n=2, s='a'))] = 6
assert d[MyClass1(n=1, s='a')] == 1
assert d[MyClass1(n=2, s='a')] == 2
assert d[MyClass1(n=2, s='b')] == 3
assert d[MyClass2(n=1, my_class_1=MyClass1(n=1, s='a'))] == 4
assert d[MyClass2(n=2, my_class_1=MyClass1(n=1, s='a'))] == 5
assert d[MyClass2(n=2, my_class_1=MyClass1(n=2, s='a'))] == 6
o = MyClass1(n=1, s='a')
try:
o.n = 2
except FrozenInstanceError as e:
pass
else:
raise 'error'
正如我们在这个例子中所看到的,哈希值是基于对象内容而不仅仅是实例地址计算的。这就是为什么像这样的东西:
d = {}
d[MyClass1(n=1, s='a')] = 1
assert d[MyClass1(n=1, s='a')] == 1
即使第二个 MyClass1(n=1, s='a')
是一个完全不同的实例,并且有不同的地址,它也能正常工作。
frozen=True
是强制性的,否则该类是不可散列的,否则用户可能会在将对象用作键之后意外修改对象,从而使容器不一致。更多文档:https://docs.python.org/zh-cn/3/library/dataclasses.html
已在 Python 3.10.7、Ubuntu 22.10 上测试。
MyThing
,如果它们有相同的name
和location
,则通过索引字典返回相同的值,即使它们作为两个不同的"对象"分别创建。 - Santa