The default implementations for __hash__
and __eq__
are inherited from the base object
type. You can find its type definition in typeobject.c
:
PyTypeObject PyBaseObject_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"object", /* tp_name */
…
(hashfunc)_Py_HashPointer, /* tp_hash */
…
object_richcompare, /* tp_richcompare */
…
};
For the hash function (tp_hash
), the default hash function for references is used, _Py_HashPointer
. It is defined in pyhash.c
:
Py_hash_t
_Py_HashPointer(void *p)
{
Py_hash_t x;
size_t y = (size_t)p;
/* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
excessive hash collisions for dicts and sets */
y = (y >> 4) | (y << (8 * SIZEOF_VOID_P - 4));
x = (Py_hash_t)y;
if (x == -1)
x = -2;
return x;
}
This basically uses the pointer address as a base for the hash.
When __eq__
is called, what Python does under the hood is perform a rich comparison (tp_richcompare
). This includes both equality and non-equality check as well as comparisons like greater or lower than. The default implementation is using object_richcompare
which requires a reference equality:
static PyObject *
object_richcompare(PyObject *self, PyObject *other, int op)
{
PyObject *res;
switch (op) {
case Py_EQ:
/* Return NotImplemented instead of False, so if two
objects are compared, both get a chance at the
comparison. See issue #1393. */
res = (self == other) ? Py_True : Py_NotImplemented;
Py_INCREF(res);
break;
…
}
return res;
}