diff options
author | wangxiang-hz <34048878+wangxiang-hz@users.noreply.github.com> | 2023-03-11 11:11:37 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-11 11:11:37 (GMT) |
commit | aa0a73d1bc53dcb6348a869df1e775138991e561 (patch) | |
tree | 66ad74f8d199076d88e5150b999895cd15807560 | |
parent | 5ffdaf748d98da6065158534720f1996a45a0072 (diff) | |
download | cpython-aa0a73d1bc53dcb6348a869df1e775138991e561.zip cpython-aa0a73d1bc53dcb6348a869df1e775138991e561.tar.gz cpython-aa0a73d1bc53dcb6348a869df1e775138991e561.tar.bz2 |
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.
-rw-r--r-- | Include/internal/pycore_object.h | 1 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst | 1 | ||||
-rw-r--r-- | Objects/object.c | 6 | ||||
-rw-r--r-- | Objects/typeobject.c | 9 |
4 files changed, 14 insertions, 3 deletions
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index e15685f..318e6f3 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -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) { diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst new file mode 100644 index 0000000..997bef2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst @@ -0,0 +1 @@ +Fix performance loss when accessing an object's attributes with ``__getattr__`` defined. diff --git a/Objects/object.c b/Objects/object.c index 38da4d4..dff5e2a 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -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) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f486b83..f0654c2 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -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); |