mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
- When method objects have an attribute that can be satisfied either
by the function object or by the method object, the function object's attribute usually wins. Christian Tismer pointed out that that this is really a mistake, because this only happens for special methods (like __reduce__) where the method object's version is really more appropriate than the function's attribute. So from now on, all method attributes will have precedence over function attributes with the same name.
This commit is contained in:
parent
bfd334a42d
commit
baf0f8f24d
2 changed files with 39 additions and 28 deletions
|
@ -2138,19 +2138,34 @@ static PyMemberDef instancemethod_memberlist[] = {
|
|||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
/* The getattr() implementation for PyMethod objects is similar to
|
||||
PyObject_GenericGetAttr(), but instead of looking in __dict__ it
|
||||
asks im_self for the attribute. Then the error handling is a bit
|
||||
different because we want to preserve the exception raised by the
|
||||
delegate, unless we have an alternative from our class. */
|
||||
/* Christian Tismer argued convincingly that method attributes should
|
||||
(nearly) always override function attributes.
|
||||
The one exception is __doc__; there's a default __doc__ which
|
||||
should only be used for the class, not for instances */
|
||||
|
||||
static PyObject *
|
||||
instancemethod_get_doc(PyMethodObject *im, void *context)
|
||||
{
|
||||
static PyObject *docstr;
|
||||
if (docstr == NULL) {
|
||||
docstr= PyString_InternFromString("__doc__");
|
||||
if (docstr == NULL)
|
||||
return NULL;
|
||||
}
|
||||
return PyObject_GetAttr(im->im_func, docstr);
|
||||
}
|
||||
|
||||
static PyGetSetDef instancemethod_getset[] = {
|
||||
{"__doc__", (getter)instancemethod_get_doc, NULL, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
instancemethod_getattro(PyObject *obj, PyObject *name)
|
||||
{
|
||||
PyMethodObject *im = (PyMethodObject *)obj;
|
||||
PyTypeObject *tp = obj->ob_type;
|
||||
PyObject *descr = NULL, *res;
|
||||
descrgetfunc f = NULL;
|
||||
PyObject *descr = NULL;
|
||||
|
||||
if (PyType_HasFeature(tp, Py_TPFLAGS_HAVE_CLASS)) {
|
||||
if (tp->tp_dict == NULL) {
|
||||
|
@ -2160,30 +2175,17 @@ instancemethod_getattro(PyObject *obj, PyObject *name)
|
|||
descr = _PyType_Lookup(tp, name);
|
||||
}
|
||||
|
||||
f = NULL;
|
||||
if (descr != NULL) {
|
||||
f = TP_DESCR_GET(descr->ob_type);
|
||||
if (f != NULL && PyDescr_IsData(descr))
|
||||
descrgetfunc f = TP_DESCR_GET(descr->ob_type);
|
||||
if (f != NULL)
|
||||
return f(descr, obj, (PyObject *)obj->ob_type);
|
||||
else {
|
||||
Py_INCREF(descr);
|
||||
return descr;
|
||||
}
|
||||
}
|
||||
|
||||
res = PyObject_GetAttr(im->im_func, name);
|
||||
if (res != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||
return res;
|
||||
|
||||
if (f != NULL) {
|
||||
PyErr_Clear();
|
||||
return f(descr, obj, (PyObject *)obj->ob_type);
|
||||
}
|
||||
|
||||
if (descr != NULL) {
|
||||
PyErr_Clear();
|
||||
Py_INCREF(descr);
|
||||
return descr;
|
||||
}
|
||||
|
||||
assert(PyErr_Occurred());
|
||||
return NULL;
|
||||
return PyObject_GetAttr(im->im_func, name);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(instancemethod_doc,
|
||||
|
@ -2490,7 +2492,7 @@ PyTypeObject PyMethod_Type = {
|
|||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
instancemethod_memberlist, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
instancemethod_getset, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
instancemethod_descr_get, /* tp_descr_get */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue