Skip to content Skip to sidebar Skip to footer

Precise Membership Test In Python

The in operator tests for equivalence using comparison, but Python's comparison isn't precise in the sense that True == 1 and 0 == False, yielding - >>> True in [ 1 ] True

Solution 1:

in doesn't test for equivalence at all. It checks if an item is in a container. Example:

>>> 5 in [1,2,3,4,5]
True
>>> 6 in [1,2,3,4,5]
False
>>> True in {True, False}
True
>>> "k" in ("b","c")
True

What you are looking for is is.

>>> True == 1
True
>>> True is 1
False
>>> False == 0
True
>>> False is 0
False

EDIT

After reading your edit, I don't think there is something built in in python libraries that suits your needs. What you want is basically to differentiate between int and bool (True, False). But python itself treats True and False as integers. This is because bool is a subclass of int. Which is why True == 1 and False==0 evaluates to true. You can even do:

>>> isinstance ( True, int)
True

I cannot think of anything better than your own solution, However, if your list is certain to contain any item not more than once you can use list.index()

try:
    index_val = mylist.index(subject)
except ValueError:
    index_val = None

if (index_val!=None):
    return type(subject) == type(member)

Since index is built-in, it might be a little faster, though rather inelegant.


Solution 2:

Python in operator is precise and the behavior you're complaining of is perfectly expected, since bool is a subclass of int.

Below is the excerpt of the official Python documentation describing the boolean type:

Booleans

These represent the truth values False and True. The two objects representing the values False and True are the only Boolean objects. The Boolean type is a subtype of plain integers, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings "False" or "True" are returned, respectively.

You can also have a look at PEP 285.


Solution 3:

You're looking for the is operator:

if any(x is True for x in l):
    ...

is, however, isn't exactly === from other languages. is checks identity, not just equality without type coercion. Since CPython uses string and integer interning, two objects that are equal may not be the same object:

In [19]: a = '12'

In [20]: b = '123'

In [21]: a += '3'

In [22]: a is b
Out[22]: False

In [23]: a == b
Out[23]: True

In [27]: 100001 is 100000 + 1
Out[27]: False

In [28]: 100001 == 100000 + 1
Out[28]: True

In Python 3, None, True, and False are essentially singletons, so using is for discerning True from 1 will work perfectly fine. In Python 2, however, this is possible:

In [29]: True = 1

In [31]: True is 1
Out[31]: True

Equality can be overridden __eq__ method, so you can define an object that is equal to any other object:

In [1]: %paste
    class Test(object):
        def __eq__(self, other):
            return True

## -- End pasted text --

In [2]: x = Test()

In [3]: x == None
Out[3]: True

In [4]: x == True
Out[4]: True

In [5]: x == False
Out[5]: True

In this case, how would === work? There is no general solution, so Python has no built-in method of lists that does what you want.


Post a Comment for "Precise Membership Test In Python"