In a Python expression like str in [str1, str2, str3]
or 1 in [1, 2, 3]
, does the in
operator use ==
or is
to compare the first object with the objects in the list?
It depends on the object how in
is executed; it is not the in
operator that makes the comparison, it is the object.__contains__
method that does the work.
For the Python standard container types (list
, tuple
, set
, dict
, etc.) both identity and equality are used. See the Membership test operations section of the Expressions reference documentation:
For container types such as
list
,tuple
,set
,frozenset
,dict
, orcollections.deque
, the expressionx in y
is equivalent toany(x is e or x == e for e in y)
.
is
is faster to test for, and objects having the same identity implies they are also equal.
Custom types are free to implement whatever test they want to do in their __contains__
method.
Next, if no __contains__
method is defined, but there is a __iter__
method or a __getitem__
method, then an iterative search is preformed where the values produced are tested for both identity and equality again. See the above linked documentation for details; the documentation is not that explicit about the identity test but the implementation still uses identity because using it is a performance boost.
You can see this when you use float('nan')
, which is never equal to itself or anything else:
>>> nan = float('nan')
>>> nan == nan
False
>>> nan is nan
True
>>> nan in [nan] # tests for identity first
True
>>> nan in iter([nan]) # an iterator, only __iter__ is defined
True
float('nan')
is an exception to the normal expectation that identity implies equality; see What is the rationale for all comparisons returning false for IEEE754 NaN values? for why that is.