下面是一个示例,其中数据类“无法”进行哈希处理,但普通类确实可以生成良好的哈希值。
既然普通类也有 np.ndarray
并且应该是不可散列的,为什么这个可以工作?
import numpy as np
from dataclasses import dataclass
class X:
def __init__(self):
x = np.ndarray([0,1,1,0,110])
@dataclass(frozen=True, eq=True)
class Y:
name: str
unit_price: np.ndarray
a = X()
print(a.__hash__())
b = Y(10, np.array([0,1,2]))
print(b.__hash__())
输出:
8787234869218
Traceback (most recent call last):
File "t.py", line 37, in <module>
print(b.__hash__())
File "<string>", line 3, in __hash__
TypeError: unhashable type: 'numpy.ndarray'
最佳答案
因为你使用了:
@dataclass(frozen=True, eq=True)
这里的规则在docs中有描述。 :
If
eq
andfrozen
are both true, by defaultdataclass()
will generate a__hash__()
method for you. Ifeq
is true andfrozen
is false,__hash__()
will be set to None, marking it unhashable (which it is, since it is mutable). Ifeq
is false,__hash__()
will be left untouched meaning the__hash__()
method of the superclass will be used (if the superclass isobject
, this means it will fall back to id-based hashing).
数据类生成了一个哈希函数,该函数基于属性进行哈希处理。当然,它实际上不起作用,因为您使用了 numpy.ndarray
。
默认情况下,用户定义的对象继承object.__hash__
,它只是根据身份进行散列,几乎返回id(self)
(尽管不完全是)。
在第一种情况下,两者的行为不会相同,因为您告诉数据类代码生成器使用相应的 __eq__
创建一个“不可变”类型,该类型基于目的。当然,散列与__eq__
一致并且基于属性的值。在第二种情况下,哈希(和相等)基于对象的身份。
为了说明这些差异:
>>> from dataclasses import dataclass
>>> @dataclass(frozen=True, eq=True)
... class Point1:
... x: int
... y: int
...
>>> points = set()
>>> points.add(Point1(0, 0))
>>> Point1(0, 0) in points
True
所以请注意,集合中有一个具有相同值的不同点对象。
但是,以下是基于身份的哈希/相等的运作方式:
>>> class Point2:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> p = Point2(0, 0)
>>> points = set()
>>> points.add(p)
>>> Point2(0, 0) in points
False
>>> p in points
True
关于python - 普通类的哈希函数是什么?为什么数据类没有相同的哈希函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71059306/