SparkAndShine
SparkAndShine

Reputation: 18017

What is the source code of __hash__() and __eq__() of object in Python?

object is a base for all new style classes. Where can I find the source code of object? I'd like to have a look how the function __hash__() and __eq__() are defined.

Refer to this answer (Finding the source code for built-in Python functions?), I search the object definition in cpython.

There is not __hash__() and __eq__() definiton in https://hg.python.org/cpython/file/tip/Objects/object.c.

Upvotes: 2

Views: 1066

Answers (2)

user2357112
user2357112

Reputation: 280973

The object implementation is actually in Objects/typeobject.c, for some reason. Looking in that file, you can see from the PyBaseObject_Type definition:

PyTypeObject PyBaseObject_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "object",                                   /* tp_name */
    ...
    (hashfunc)_Py_HashPointer,                  /* tp_hash */
    ...
    object_richcompare,                         /* tp_richcompare */

that object.__eq__ is implemented in object_richcompare, and object.__hash__ is implemented in _Py_HashPointer from Python/pyhash.c.

In Python 2.7:

PyTypeObject PyBaseObject_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "object",                                   /* tp_name */
    ...
    0,                                          /* tp_compare */
    ...
    (hashfunc)_Py_HashPointer,                  /* tp_hash */
    ...
    0,                                          /* tp_richcompare */

object.__eq__ simply doesn't exist, so == ultimately falls back on a pointer comparison in default_3way_compare. _Py_HashPointer still exists, but it's in Objects/object.c

Upvotes: 2

poke
poke

Reputation: 387755

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;
}

Upvotes: 4

Related Questions