diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2008-07-15 14:27:37 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2008-07-15 14:27:37 (GMT) |
commit | 53663a695ef2bb96ac0252cd4cc4aa40d4f953be (patch) | |
tree | e241ef71b353f8b3162179b1eed5a3f4eaae0c5f /Objects | |
parent | 9ace15ca25e1e72e1b943190a5f4efbd7d118de3 (diff) | |
download | cpython-53663a695ef2bb96ac0252cd4cc4aa40d4f953be.zip cpython-53663a695ef2bb96ac0252cd4cc4aa40d4f953be.tar.gz cpython-53663a695ef2bb96ac0252cd4cc4aa40d4f953be.tar.bz2 |
Issue 2235: __hash__ is once again inherited by default, but inheritance can be blocked explicitly so that collections.Hashable remains meaningful
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/dictobject.c | 2 | ||||
-rw-r--r-- | Objects/listobject.c | 2 | ||||
-rw-r--r-- | Objects/object.c | 11 | ||||
-rw-r--r-- | Objects/setobject.c | 2 | ||||
-rw-r--r-- | Objects/typeobject.c | 68 |
5 files changed, 35 insertions, 50 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 5791165..038f373 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2240,7 +2240,7 @@ PyTypeObject PyDict_Type = { 0, /* tp_as_number */ &dict_as_sequence, /* tp_as_sequence */ &dict_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)PyObject_HashNotImplemented, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ diff --git a/Objects/listobject.c b/Objects/listobject.c index 16a2ce6..10f2c5d 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2742,7 +2742,7 @@ PyTypeObject PyList_Type = { 0, /* tp_as_number */ &list_as_sequence, /* tp_as_sequence */ &list_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)PyObject_HashNotImplemented, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ diff --git a/Objects/object.c b/Objects/object.c index f40fd9f..9cd34b8 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1083,6 +1083,13 @@ finally: #endif } +long +PyObject_HashNotImplemented(PyObject *self) +{ + PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", + self->ob_type->tp_name); + return -1; +} long PyObject_Hash(PyObject *v) @@ -1094,9 +1101,7 @@ PyObject_Hash(PyObject *v) return _Py_HashPointer(v); /* Use address as hash value */ } /* If there's a cmp but no hash defined, the object can't be hashed */ - PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", - v->ob_type->tp_name); - return -1; + return PyObject_HashNotImplemented(v); } PyObject * diff --git a/Objects/setobject.c b/Objects/setobject.c index 39465f3..fbbdf6e 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2109,7 +2109,7 @@ PyTypeObject PySet_Type = { &set_as_number, /* tp_as_number */ &set_as_sequence, /* tp_as_sequence */ 0, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)PyObject_HashNotImplemented, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e0ae55b..0af3f30 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3648,27 +3648,6 @@ inherit_special(PyTypeObject *type, PyTypeObject *base) type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS; } -static char *hash_name_op[] = { - "__eq__", - "__cmp__", - "__hash__", - NULL -}; - -static int -overrides_hash(PyTypeObject *type) -{ - char **p; - PyObject *dict = type->tp_dict; - - assert(dict != NULL); - for (p = hash_name_op; *p; p++) { - if (PyDict_GetItemString(dict, *p) != NULL) - return 1; - } - return 0; -} - static void inherit_slots(PyTypeObject *type, PyTypeObject *base) { @@ -3802,8 +3781,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) { if (type->tp_compare == NULL && type->tp_richcompare == NULL && - type->tp_hash == NULL && - !overrides_hash(type)) + type->tp_hash == NULL) { type->tp_compare = base->tp_compare; type->tp_richcompare = base->tp_richcompare; @@ -3984,18 +3962,6 @@ PyType_Ready(PyTypeObject *type) } } - /* Hack for tp_hash and __hash__. - If after all that, tp_hash is still NULL, and __hash__ is not in - tp_dict, set tp_dict['__hash__'] equal to None. - This signals that __hash__ is not inherited. - */ - if (type->tp_hash == NULL && - PyDict_GetItemString(type->tp_dict, "__hash__") == NULL && - PyDict_SetItemString(type->tp_dict, "__hash__", Py_None) < 0) - { - goto error; - } - /* Some more special stuff */ base = type->tp_base; if (base != NULL) { @@ -5280,10 +5246,8 @@ slot_tp_hash(PyObject *self) func = lookup_method(self, "__cmp__", &cmp_str); } if (func != NULL) { - PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", - self->ob_type->tp_name); Py_DECREF(func); - return -1; + return PyObject_HashNotImplemented(self); } PyErr_Clear(); h = _Py_HashPointer((void *)self); @@ -6034,6 +5998,13 @@ update_one_slot(PyTypeObject *type, slotdef *p) sanity checks. I'll buy the first person to point out a bug in this reasoning a beer. */ } + else if (descr == Py_None && + strcmp(p->name, "__hash__") == 0) { + /* We specifically allow __hash__ to be set to None + to prevent inheritance of the default + implementation from object.__hash__ */ + specific = PyObject_HashNotImplemented; + } else { use_generic = 1; generic = p->function; @@ -6247,12 +6218,21 @@ add_operators(PyTypeObject *type) continue; if (PyDict_GetItem(dict, p->name_strobj)) continue; - descr = PyDescr_NewWrapper(type, p, *ptr); - if (descr == NULL) - return -1; - if (PyDict_SetItem(dict, p->name_strobj, descr) < 0) - return -1; - Py_DECREF(descr); + if (*ptr == PyObject_HashNotImplemented) { + /* Classes may prevent the inheritance of the tp_hash + slot by storing PyObject_HashNotImplemented in it. Make it + visible as a None value for the __hash__ attribute. */ + if (PyDict_SetItem(dict, p->name_strobj, Py_None) < 0) + return -1; + } + else { + descr = PyDescr_NewWrapper(type, p, *ptr); + if (descr == NULL) + return -1; + if (PyDict_SetItem(dict, p->name_strobj, descr) < 0) + return -1; + Py_DECREF(descr); + } } if (type->tp_new != NULL) { if (add_tp_new_wrapper(type) < 0) |