John Millikin 提出了一个类似这样的解决方案:
class A(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
def __eq__(self, othr):
return (isinstance(othr, type(self))
and (self._a, self._b, self._c) ==
(othr._a, othr._b, othr._c))
def __hash__(self):
return hash((self._a, self._b, self._c))
这个解决方案的问题是hash(A(a, b, c)) == hash((a, b, c)).换句话说,散列与其关键成员的元组的散列相冲突。也许这在实践中并不重要?
更新:Python 文档现在建议使用上面示例中的元组。请注意,文档说明
唯一需要的属性是比较相等的对象具有相同的哈希值
请注意,相反的情况并非如此。比较不相等的对象可能具有相同的哈希值。这种哈希冲突不会导致一个对象在用作字典键或集合元素时替换另一个对象只要对象不也比较相等。
过时/糟糕的解决方案
Python documentation on __hash__ 建议使用 XOR 之类的东西来组合子组件的哈希,这给了我们这样的结果:
class B(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
def __eq__(self, othr):
if isinstance(othr, type(self)):
return ((self._a, self._b, self._c) ==
(othr._a, othr._b, othr._c))
return NotImplemented
def __hash__(self):
return (hash(self._a) ^ hash(self._b) ^ hash(self._c) ^
hash((self._a, self._b, self._c)))
更新:正如 Blckknght 指出的那样,更改 a、b 和 c 的顺序可能会导致问题。我添加了一个额外的^ hash((self._a, self._b, self._c)) 来捕获被散列的值的顺序。如果无法重新排列组合的值(例如,如果它们具有不同的类型,因此_a 的值将永远不会分配给_b 或_c 等),则可以删除最后的^ hash(...)。