像这样实施__hash__
是一个坏主意吗?
class XYZ:
def __init__(self):
self.val = None
def __hash__(self):
return id(self)
我是否设置了可能带来灾难性的东西?
__hash__
方法必须满足以下要求才能工作:
Forall x,y使x == y
,然后hash(x) == hash(y)
。
在你的情况下,你的类没有实现__eq__
,这意味着x == y
当且仅当id(x) == id(y)
,因此你的哈希实现满足上述属性。
但请注意,如果您实现__eq__
,那么此实现可能会失败。
另外:拥有一个“有效”的__hash__
和一个好的哈希之间存在差异。例如,以下是任何类的有效__hash__
定义:
def __hash__(self):
return 1
一个好的哈希应该尝试统一分布对象,以尽可能避免冲突。通常这需要更复杂的定义。我会避免尝试提出公式,而是依赖python内置的hash
函数。
例如,如果你的类有字段a
,b
和c
那么我会使用像__hash__
这样的东西:
def __hash__(self):
return hash((self.a, self.b, self.c))
hash
对于元组的定义对于普通情况应该足够好。
最后:你不应该在可变的类中定义__hash__
(在用于相等的字段中)。那是因为修改实例会改变它们的哈希值,这会破坏事情。
这要么是毫无意义,要么是错误的,这取决于班上的其他人。
如果你的对象使用默认的基于身份的==
,那么定义这个__hash__
是没有意义的。默认的__hash__
也是基于身份的,但速度更快,并且经过调整以避免始终将低位设置为0.使用默认的__hash__
会更简单,更高效。
如果你的对象不使用默认的基于身份的==
,那么你的__hash__
是错误的,因为它会与==
不一致。如果你的对象是不可变的,你应该以与__hash__
一致的方式实现==
;如果你的对象是可变的,你根本不应该实现__hash__
(如果需要支持Python 2,则设置__hash__ = None
)。
这是__hash__
的默认实现。请注意,__eq__
的填充导致默认的__hash__
实现消失。如果你重新实现__hash__
,那么任何比较相等的对象必须具有相同的哈希值。
但是,对于不相等的对象,可以使用相同的哈希值。因此,使用返回常量值的哈希实现始终是安全的。但是,效率非常低。
适用于大量用例的一个很好的默认值是返回__eq__
方法中使用的属性元组的哈希值。例如。
class XYZ:
def __init__(self, val0, val1):
self.val0 = val0
self.val1 = val1
def __eq__(self, other):
return self.val0 == other.val1 and self.val1 == other.val1
def __hash__(self):
return hash((self.val0, self.val1))