Consider the following code:
>>> 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
So, in
seems to use __eq__
to determine whether or not something is in a container.
in
use object identity, a.k.a. a in somelist
if the object a
is in somelist
, and not some other object that compares equal to a
?Use the any()
function and a generator expression:
any(o is a for o in l)
The behaviour of in
is documented in the Common Sequence Operators section:
x in s
True
if an item of s is equal to x, elseFalse
Bold emphasis mine.
If you must use in
, use a wrapper object with a custom __eq__
method that uses is
, or build your own container where a custom __contains__
method uses is
to test against each contained element.
The wrapper could look like this:
class IdentityWrapper(object):
def __init__(self, ob):
self.ob = ob
def __eq__(self, other):
return other is self.ob
Demo:
>>> IdentityWrapper(a) in l
False
>>> IdentityWrapper(a) in (l + [a])
True
The container could just use the same any()
function outlined above:
class IdentityList(list):
def __contains__(self, other):
return any(o is other for o in self)
Demo:
>>> il = IdentityList(l)
>>> a in il
False
>>> a in IdentityList(l + [a])
True