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