Python * list *" in" operator:相等,哈希检查还是身份?

时间:2018-02-18 10:51:43

标签: python operators contains

评论中的那些人要求我提供我的实际代码,所以我删除了旧的例子。

我正在制作this,我希望两个Page具有相同的标题来比较相等。我已经对Page class:

这样做了
def __eq__(self, other):
    return self.title == other.title

但如果我这样做,那就不是真的:

>>> import mw_api_client as mwc
>>> w = mwc.Wiki('https://en.wikipedia.org/w/api.php')
>>> a = [w.page(str(i)) for i in range(20)]
>>> w.page('0') in a
False

我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:1)

列表的__contains __方法记录在此处的“成员资格测试”部分中:

https://docs.python.org/3.6/reference/expressions.html#membership-test-details

  

对于容器类型,例如list,tuple,set,frozenset,dict或collections.deque,表达式x in y等同于any(x is e or x == e for e in y)

对于您的特定用例,您需要覆盖__contains__ - 但是您不能只覆盖列表中的__contains__ - 例如:

a = []
a.__contains__ = lambda: True
AttributeError: 'list' object attribute '__contains__' is read-only

因此,解决方案是创建一个包装列表的自定义类,并提供自己的__contains__方法。类似下面的内容(注意我在这个例子中使用了dicts,因此obj['title']而不是obj.title - 您可能还想在__contains__中测试更多内容,例如类型比较等。我在这里使用UserList,因为它提供了一个很好的list类来继承,并使列表内容在data中可用:

from collections import UserList

class MyList(UserList):
    def __init__(self, lst):
        self.data = lst

    def __contains__(self, obj):
        """Return True if any item in the list has a title, and the title matches that of the passed-in dict"""
        return any(obj['title'] == x['title'] for x in self.data if 'title' in x)

mr = {"title": "mr"}
mrs = {"title": "mrs"}
dr = {"title": "dr"}
random = {"foo": "bar"}


x = [mr, mrs, random]

y = MyList(x)

print(mr in y) # True
print(dr in y) # False
y.append(dr)
print(dr in y) # True