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.
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) {
--- /dev/null
+Fix performance loss when accessing an object's attributes with ``__getattr__`` defined.
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)
(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);