请考虑以下代码:
>>> 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__
来确定某个容器中是否存在某些内容。
in
使用对象标识,如果对象a in somelist
在a
中,则为somelist
,而不是与a
进行比较的其他对象1}}?答案 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