While numpy.nan
is not equal to numpy.nan
, and (float('nan'), 1)
is not equal to float('nan', 1)
,
(numpy.nan, 1) == (numpy.nan, 1)
What could be the reason? Does Python first check to see if the ids are identical? If identity is checked first when comparing items of a tuple, then why isn't it checked when objects are compared directly?
When you do numpy.nan == numpy.nan
it's numpy that is deciding whether the condition is true or not. When you compare tuples
python is just checking if the tuples have the same objects which they do. You can make numpy
have the decision by turning the tuples
into numpy
arrays.
np.array((1, numpy.nan)) == np.array((1,numpy.nan))
>>array([ True, False], dtype=bool)
The reason is when you do ==
with numpy
objects you're calling the numpy function __eq__()
that says specifically that nan != nan
because mathematically speaking nan
is undetermined (could be anything) so it makes sense that nan != nan
. But when you do ==
with tuples you call the tuples __eq__()
function that doesn't care about mathematics and only cares if python objects are the same or not. In case of (float('nan'),1)==(float('nan'),1)
it returns False
because each call of float('nan')
allocates memory in a different place as you can check by doing float('nan') is float('nan')
.
Container objects are free to define what equality means for them, and for most that means one thing is really, really important:
for x in container:
assert x in container
So containers typically do an id
check before an __eq__
check.
When comparing two objects in a tuple Python first check to see if they are the same.
Note that numpy.nan is numpy.nan
, but float('nan') is not float('nan')
.
In Objects/tupleobject.c
, the comparison is carried out like this:
for (i = 0; i < vlen && i < wlen; i++) {
int k = PyObject_RichCompareBool(vt->ob_item[i],
wt->ob_item[i], Py_EQ);
if (k < 0)
return NULL;
if (!k)
break;
}
And in PyObject_RichCompareBool
, you can see the check for equality:
if (v == w) {
if (op == Py_EQ)
return 1;
else if (op == Py_NE)
return 0;
}
You can verify this with the following example:
class A(object):
def __eq__(self, other):
print "Checking equality with __eq__"
return True
a1 = A()
a2 = A()
If you try (a1, 1) == (a1, 1)
nothing get printed, while (a1, 1) == (a2, 1)
would use __eq__
and print our the message.
Now try a1 == a1
and see if it surprises you ;P
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With