mirror of https://github.com/python/cpython
gh-102213: Optimize the performance of `__getattr__` (GH-102248)
When __getattr__ is defined, python with try to find an attribute using _PyObject_GenericGetAttrWithDict find nothing is reasonable so we don't need an exception, it will hurt performance.
This commit is contained in:
parent
5ffdaf748d
commit
aa0a73d1bc
|
@ -370,6 +370,7 @@ extern void _PyObject_FreeInstanceAttributes(PyObject *obj);
|
|||
extern int _PyObject_IsInstanceDictEmpty(PyObject *);
|
||||
extern int _PyType_HasSubclasses(PyTypeObject *);
|
||||
extern PyObject* _PyType_GetSubclasses(PyTypeObject *);
|
||||
extern PyObject* _PyObject_GenericTryGetAttr(PyObject *, PyObject *);
|
||||
|
||||
// Access macro to the members which are floating "behind" the object
|
||||
static inline PyMemberDef* _PyHeapType_GET_MEMBERS(PyHeapTypeObject *etype) {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fix performance loss when accessing an object's attributes with ``__getattr__`` defined.
|
|
@ -1405,6 +1405,12 @@ PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
|
|||
return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 0);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyObject_GenericTryGetAttr(PyObject *obj, PyObject *name)
|
||||
{
|
||||
return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 1);
|
||||
}
|
||||
|
||||
int
|
||||
_PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
|
||||
PyObject *value, PyObject *dict)
|
||||
|
|
|
@ -8247,14 +8247,17 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name)
|
|||
(Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) &&
|
||||
((PyWrapperDescrObject *)getattribute)->d_wrapped ==
|
||||
(void *)PyObject_GenericGetAttr))
|
||||
res = PyObject_GenericGetAttr(self, name);
|
||||
/* finding nothing is reasonable when __getattr__ is defined */
|
||||
res = _PyObject_GenericTryGetAttr(self, name);
|
||||
else {
|
||||
Py_INCREF(getattribute);
|
||||
res = call_attribute(self, getattribute, name);
|
||||
Py_DECREF(getattribute);
|
||||
}
|
||||
if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear();
|
||||
if (res == NULL) {
|
||||
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear();
|
||||
}
|
||||
res = call_attribute(self, getattr, name);
|
||||
}
|
||||
Py_DECREF(getattr);
|
||||
|
|
Loading…
Reference in New Issue