Pretty much anyone who works with IEEE floating-point values has run into NaN, or "not a number", at some point. Famously, NaN is not equal to itself.
>>> x = float('nan')
>>> x == x
False
Now, I had come to terms with this, but there's a strange behavior I'm struggling to wrap my head around. Namely,
>>> x in [x]
True
I had always assumed that list.__contains__
was written something like
def __contains__(self, element):
for x in self:
if element == x:
return True
return False
i.e., it used __eq__
on the relevant data type internally. And indeed it does. If I define a custom class with an __eq__
method of my own design, then I can verify that Python does in fact call __eq__
when doing the inclusion check. But then how can there exist a value x
(NaN in our case) such that x == x
is false but x in [x]
is true?
We can observe the same behavior with a custom __eq__
as well.
class Example:
def __eq__(self, other):
return False
x = Example()
print(x == x) # False
print(x in [x]) # True