Python - 当识别到重复项时,集合或不可变集合采用哪个对象?
我有一个自己定义的类 MyClass
,里面实现了 __hash__
和 __eq__
方法,这样可以确保,比如说:
>>> a = MyClass([100, 99, 98, 97])
>>> b = MyClass([99, 98, 97, 100])
>>> a.__hash__() == b.__hash__()
True
>>> a == b
True
问题是:如果我这样做:
>>> x = [a, b]
>>> set(x)
我能相信 set
会保留 a
吗?这个集合的 __init__
是按顺序遍历 x
吗?还是说我需要担心它会随机取 b
呢?
谢谢,
迈克
3 个回答
1
set
(集合)和 dict
(字典)不仅会检查两个对象的哈希值是否相等,还会比较这两个对象本身是否相等。
1
我认为使用set()的时候,需要同时重写hash和eq这两个方法。这样的话,你可能会遇到hash(a)和hash(b)是相等的,但实际上a和b却不相等,这种情况是因为你定义的eq方法是这样设计的。
3
在这些基于哈希的情况中,它会同时使用 __hash__
和 __eq__
。
如果 __hash__
和 __eq__
的结果是一样的,那么在可迭代对象中,首先遇到的那个就会被选中。当它遇到下一个时,会检查是否已经存在这个元素,如果存在,就会决定是的。
>>> class Same(object):
... def __init__(self, value):
... self.value = value
... def __hash__(self):
... return 42
... def __eq__(self, other):
... return True
... def __repr__(self):
... return 'Same(%r)' % self.value
>>> set([Same(2), Same(1)])
set([Same(2)])
>>> set([Same(1), Same(2)])
set([Same(1)])
对于 dict
来说,这就变得更有趣了:
>>> {Same(1): 1, Same(2): 2}
{Same(1): 2}
>>> {Same(1): 2, Same(2): 1}
{Same(1): 1}
>>> {Same(2): 1, Same(2): 2}
{Same(2): 2}
>>> {Same(2): 2, Same(2): 1}
{Same(2): 1}
>>> {Same(2): 2, Same(2): 1}
{Same(2): 1}
你应该能猜到这里发生了什么。它会存储第一个项目,然后第二个项目的哈希值和相等性是一样的;但是,它的值不同,所以会存储这个新的值。无论它们是否匹配,值总是会被覆盖:
>>> {Same(1): Same(2), Same(3): Same(4)}
{Same(1): Same(4)}
希望这能帮到你。