【问题标题】:Check if object is in list (not "by value", but by id)检查对象是否在列表中(不是“按值”,而是按 id)
【发布时间】:2023-03-22 20:59:01
【问题描述】:

考虑以下代码:

>>> 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. 如果对象asomelist 中,而不是与a 比较的其他对象,是否可以使in 使用对象标识,即a in somelist

【问题讨论】:

标签: python comparison-operators


【解决方案1】:

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

any(o is a for o in l)

in 的行为记录在Common Sequence Operators section

x in s
True如果s中的一项等于 x,否则False

我的大胆强调。

如果您必须使用in,请使用带有自定义__eq__ 方法的包装器对象,该方法使用is,或者构建您自己的容器,其中自定义__contains__ method 使用is 来测试每个包含的元素。

包装器可能如下所示:

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

【讨论】:

  • in 不使用__contains__
  • @DeepSpace:是的,如果你正在编写一个序列,你应该定义 __contains__ 以便它完成这个答案所描述的。
  • 我认为in使用了容器的__contains__方法,而容器又使用了__eq__
【解决方案2】:

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

调用以实现成员资格测试运算符。应该返回 true 如果 item 在 self 中,否则为 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    • 2022-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-21
    相关资源
    最近更新 更多