The function cannot fail: it cannot return ``-1``.
.. versionadded:: 3.13
+
+.. c:function:: Py_hash_t PyObject_GenericHash(PyObject *obj)
+
+ Generic hashing function that is meant to be put into a type
+ object's ``tp_hash`` slot.
+ Its result only depends on the object's identity.
+
+ .. impl-detail::
+ In CPython, it is equivalent to :c:func:`Py_HashPointer`.
+
+ .. versionadded:: 3.13
:c:member:`~PyTypeObject.tp_richcompare` and :c:member:`~PyTypeObject.tp_hash`, when the subtype's
:c:member:`~PyTypeObject.tp_richcompare` and :c:member:`~PyTypeObject.tp_hash` are both ``NULL``.
+ **Default:**
+
+ :c:data:`PyBaseObject_Type` uses :c:func:`PyObject_GenericHash`.
+
.. c:member:: ternaryfunc PyTypeObject.tp_call
* Add :c:func:`Py_HashPointer` function to hash a pointer.
(Contributed by Victor Stinner in :gh:`111545`.)
+* Add :c:func:`PyObject_GenericHash` function that implements the default
+ hashing function of a Python object.
+ (Contributed by Serhiy Storchaka in :gh:`113024`.)
+
* Add PyTime C API:
* :c:type:`PyTime_t` type.
PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void);
PyAPI_FUNC(Py_hash_t) Py_HashPointer(const void *ptr);
+PyAPI_FUNC(Py_hash_t) PyObject_GenericHash(PyObject *);
self.assertTrue(number_check(0.5))
self.assertFalse(number_check("1 + 1j"))
+ def test_object_generichash(self):
+ # Test PyObject_GenericHash()
+ generichash = _testcapi.object_generichash
+ for obj in object(), 1, 'string', []:
+ self.assertEqual(generichash(obj), object.__hash__(obj))
+
if __name__ == "__main__":
unittest.main()
--- /dev/null
+Add :c:func:`PyObject_GenericHash` function.
return -1;
}
else if (mpd_isnan(MPD(v))) {
- return _Py_HashPointer(v);
+ return PyObject_GenericHash((PyObject *)v);
}
else {
return py_hash_inf * mpd_arith_sign(MPD(v));
}
+static PyObject *
+object_generichash(PyObject *Py_UNUSED(module), PyObject *arg)
+{
+ NULLABLE(arg);
+ Py_hash_t hash = PyObject_GenericHash(arg);
+ Py_BUILD_ASSERT(sizeof(long long) >= sizeof(hash));
+ return PyLong_FromLongLong(hash);
+}
+
+
static PyMethodDef test_methods[] = {
{"hash_getfuncdef", hash_getfuncdef, METH_NOARGS},
{"hash_pointer", hash_pointer, METH_O},
+ {"object_generichash", object_generichash, METH_O},
{NULL},
};
method_hash(PyMethodObject *a)
{
Py_hash_t x, y;
- x = _Py_HashPointer(a->im_self);
+ x = PyObject_GenericHash(a->im_self);
y = PyObject_Hash(a->im_func);
if (y == -1)
return -1;
{
wrapperobject *wp = (wrapperobject *)self;
Py_hash_t x, y;
- x = _Py_HashPointer(wp->self);
+ x = PyObject_GenericHash(wp->self);
y = _Py_HashPointer(wp->descr);
x = x ^ y;
if (x == -1)
meth_hash(PyCFunctionObject *a)
{
Py_hash_t x, y;
- x = _Py_HashPointer(a->m_self);
+ x = PyObject_GenericHash(a->m_self);
y = _Py_HashPointer((void*)(a->m_ml->ml_meth));
x ^= y;
if (x == -1)
"When called, it accepts no arguments and returns a new featureless\n"
"instance that has no instance attributes and cannot be given any.\n");
-static Py_hash_t
-object_hash(PyObject *obj)
-{
- return _Py_HashPointer(obj);
-}
-
PyTypeObject PyBaseObject_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"object", /* tp_name */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- object_hash, /* tp_hash */
+ PyObject_GenericHash, /* tp_hash */
0, /* tp_call */
object_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
/* Just use the address.
XXX - should we use the handle value?
*/
- return _Py_HashPointer(ob);
+ return PyObject_GenericHash(ob);
}
if (Py_IS_INFINITY(v))
return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
else
- return _Py_HashPointer(inst);
+ return PyObject_GenericHash(inst);
}
m = frexp(v, &e);
return hash;
}
+Py_hash_t
+PyObject_GenericHash(PyObject *obj)
+{
+ return Py_HashPointer(obj);
+}
+
Py_hash_t
_Py_HashBytes(const void *src, Py_ssize_t len)
{