Python 2: 'in'关键字在集合和列表中的不同含义

9 投票
3 回答
1746 浏览
提问于 2025-04-17 12:56

考虑这个代码片段:

class SomeClass(object):

    def __init__(self, someattribute="somevalue"):
        self.someattribute = someattribute

    def __eq__(self, other):
        return self.someattribute == other.someattribute

    def __ne__(self, other):
        return not self.__eq__(other)

list_of_objects = [SomeClass()]
print(SomeClass() in list_of_objects)

set_of_objects = set([SomeClass()])
print(SomeClass() in set_of_objects)

它的结果是:

True
False

有没有人能解释一下,为什么'in'这个关键词在集合和列表中的含义不同呢?我本来以为它们都应该返回True,特别是当被测试的类型已经定义了相等的方法时。

3 个回答

1

定义一个 __hash__() 方法,这个方法要和你的 __eq__() 方法相对应。示例.

3

在几乎所有的哈希表实现中,包括Python的,如果你重写了相等性的方法,就必须重写哈希的方法(在Python中,这个方法叫做 __hash__)。对于列表来说,in 操作符只是检查列表中每个元素是否相等。而对于集合来说,in 操作符首先会对你要查找的对象进行哈希处理,然后在哈希表的相应位置检查是否有这个对象,最后如果这个位置有东西,它才会检查是否相等。所以,如果你只重写了 __eq__ 而没有重写 __hash__,那么你就不能保证集合的 in 操作符会在正确的位置进行检查。

17

意思是一样的,但实现方式不同。列表会逐个检查每个对象,看它们是否相等,所以在你的类中可以正常工作。而集合则是先对对象进行哈希处理,如果对象没有正确实现哈希功能,集合就会看起来不正常。

你的类定义了 __eq__,但没有定义 __hash__,因此在集合中或作为字典的键时就无法正常工作。关于 __eq____hash__ 的规则是:两个通过 __eq__ 判断为相等的对象,它们的哈希值也必须相等。默认情况下,对象的哈希值是基于它们的内存地址生成的。所以,按照你的定义,相等的两个对象并没有提供相同的哈希值,这就违反了 __eq____hash__ 的规则。

如果你提供一个 __hash__ 的实现,它就能正常工作。对于你的示例代码,可以是:

def __hash__(self):
    return hash(self.someattribute)

撰写回答