假设我在 python3 中有一个数据类。我希望能够对这些对象进行散列和排序。
我只希望它们在 id 上排序/散列。
我在文档中看到我可以实现
__hash__
以及所有这些,但我希望让 datacalsses 为我完成这项工作,因为它们旨在处理这个问题。
from dataclasses import dataclass, field
@dataclass(eq=True, order=True)
class Category:
id: str = field(compare=True)
name: str = field(default="set this in post_init", compare=False)
a = sorted(list(set([ Category(id='x'), Category(id='y')])))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Category'
来自文档:
以下是管理
方法隐式创建的规则:__hash__()
[...]
如果
和eq
都为 true,默认情况下frozen
将 为您生成一个dataclass()
方法。如果__hash__()
为 true 并且eq
为 false,frozen
将被设置为__hash__()
,将其标记为不可散列 (确实如此,因为它是可变的)。如果None
为假,则eq
将保持不变,这意味着 的__hash__()
方法 将使用超类(如果超类是对象,这意味着它 将回退到基于 id 的哈希)。__hash__()
由于您设置了
eq=True
并将 frozen
保留为默认值 (False
),因此您的数据类是不可散列的。
您有 3 个选择:
frozen=True
(除了eq=True
之外),这将使您的类不可变且可散列。Set
unsafe_hash=True
,这将创建一个 __hash__
方法,但使您的类可变,因此,如果您的类的实例在存储在字典或集合中时被修改,则可能会出现问题:
cat = Category('foo', 'bar')
categories = {cat}
cat.id = 'baz'
print(cat in categories) # False
__hash__
方法。TL;博士
将
frozen=True
与 eq=True
结合使用(这将使实例不可变)。
长答案
来自文档:
由内置__hash__()
以及将对象添加到哈希集合(例如字典和集合)时使用。有一个hash()
意味着该类的实例是不可变的。可变性是一个 复杂的属性取决于程序员的意图,__hash__()
的存在和行为,以及 eq 和 的值__eq__()
装饰器中的冻结标志。dataclass()
默认情况下,
不会隐式添加dataclass()
方法 除非这样做是安全的。它也不会添加或更改现有的 明确定义的__hash__()
方法。设置类属性__hash__()
对于 Python 具有特定含义,如__hash__ = None
文档中所述。__hash__()
如果
没有显式定义,或者设置为 None,则__hash__()
可以添加隐式dataclass()
方法。虽然不是 推荐,您可以强制__hash__()
创建dataclass()
方法 与__hash__()
。如果您的班级是 逻辑上是不可变的,但仍然可以改变。这是一个 专门的用例,应仔细考虑。unsafe_hash=True
以下是管理
方法隐式创建的规则。 请注意,您不能在您的 数据类并设置__hash__()
;这将导致__hash__()
。如果 eq 和 freeze 都为 true,默认情况下unsafe_hash=True
TypeError
将生成一个
方法给你。如果 eq 为 true 并且 freeze 为 false,则dataclass()
将被设置为 None,将其标记为不可散列(确实如此,因为它是可变的)。如果 eq 为 false,则__hash__()
将被留下 不变意味着将使用超类的__hash__()
方法 (如果超类是 object,这意味着它将回退到基于 id 的 散列)。__hash__()