检查对象是否在列表中(不是"按值",但是按id)

时间:2015-12-28 18:46:15

标签: python comparison-operators

请考虑以下代码:

>>> class A(object):
...   def __init__(self, a):
...     self.a = a
...   def __eq__(self, other):
...     return self.a==other.a
... 
>>> a=A(1)
>>> b=A(1)
>>> c=A(2)

>>> a==b
True                   # because __eq__ says so
>>> a==c
False                  # because __eq__ says so
>>> a is b
False                  # because they're different objects

>>> l = [b,c]
>>> a in l
True                   # seems to use __eq__ under the hood

因此,in似乎使用__eq__来确定某个容器中是否存在某些内容。

  1. 哪里可以找到有关此行为的文档?
  2. 是否可以使in使用对象标识,如果对象a in somelista中,则为somelist,而不是与a进行比较的其他对象1}}?

2 个答案:

答案 0 :(得分:6)

使用any() function和生成器表达式:

any(o is a for o in l)

in中记录了x in s的行为:

  

True
  False如果 s 的项目等于 x ,则in

大胆强调我的。

如果您必须使用__eq__,请使用包含使用is的自定义is方法的包装器对象,或者在自定义Common Sequence Operators section使用{{}的情况下构建您自己的容器1}}测试每个包含的元素。

包装器可能如下所示:

class IdentityWrapper(object):
    def __init__(self, ob):
        self.ob = ob
    def __eq__(self, other):
        return other is self.ob

演示:

>>> IdentityWrapper(a) in l
False
>>> IdentityWrapper(a) in (l + [a])
True

容器可以使用上面列出的any()函数:

class IdentityList(list):
    def __contains__(self, other):
        return any(o is other for o in self)

演示:

>>> il = IdentityList(l)
>>> a in il
False
>>> a in IdentityList(l + [a])
True

答案 1 :(得分:4)

如果您不想更改A行为,可以为旧容器准备薄包装。要更改in运算符的行为方式,需要覆盖魔术方法__contains__。引用文档:

  

被调用以实现成员资格测试运营商。如果,应该返回true   item是自己的,否则是false。对于映射对象,这应该   考虑映射的关键而不是值或   关键项对。

示例代码:

class A(object):
    def __init__(self, a):
        self.a = a

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


class IdentityList(list):
    def __contains__(self, obj):
        return any(o is obj for o in self)

a = A(1)
b = A(1)
c = A(2)
container = [b, c]
identity_container = IdentityList(container)
assert a in container  # not desired output (described in question)
assert a not in identity_container  # desired output