Python - 当识别到重复项时,集合或不可变集合采用哪个对象?

2 投票
3 回答
602 浏览
提问于 2025-04-16 07:35

我有一个自己定义的类 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()的时候,需要同时重写hasheq这两个方法。这样的话,你可能会遇到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)}

希望这能帮到你。

撰写回答