Python 2: 'in'关键字在集合和列表中的不同含义
考虑这个代码片段:
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)