From 56762ce57ce7843c3440149d720dab4fd0d09342 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sat, 3 Dec 2022 22:50:13 +0100 Subject: [PATCH 1/2] improve performance of hasattr for type objects --- Include/internal/pycore_typeobject.h | 1 + Objects/object.c | 14 ++++++++++++++ Objects/typeobject.c | 14 ++++++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 71f3068900da31..f20fac27cbd573 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -80,6 +80,7 @@ extern static_builtin_state * _PyStaticType_GetState(PyTypeObject *); extern void _PyStaticType_ClearWeakRefs(PyTypeObject *type); extern void _PyStaticType_Dealloc(PyTypeObject *type); +PyObject *_Py_type_getattro(PyTypeObject *type, PyObject *name, int supress); PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name); PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); diff --git a/Objects/object.c b/Objects/object.c index 687bd36d2b4af1..95d9f7a47fcdae 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -980,6 +980,20 @@ int PyObject_HasAttr(PyObject *v, PyObject *name) { PyObject *res; + + if (Py_IS_TYPE(v, &PyType_Type)) // exact type object + { + PyObject *result = _Py_type_getattro((PyTypeObject*)v, name, 1); + if (result != NULL) { + return 1; + } + if (PyErr_Occurred()) { + PyErr_Clear(); + return 0; + } + return 0; + } + if (_PyObject_LookupAttr(v, name, &res) < 0) { PyErr_Clear(); return 0; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ae80f5a8fd88e0..a54c9890aad854 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4237,8 +4237,8 @@ is_dunder_name(PyObject *name) /* This is similar to PyObject_GenericGetAttr(), but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ -static PyObject * -type_getattro(PyTypeObject *type, PyObject *name) +PyObject * +_Py_type_getattro(PyTypeObject *type, PyObject *name, int suppress_exception) { PyTypeObject *metatype = Py_TYPE(type); PyObject *meta_attribute, *attribute; @@ -4318,12 +4318,22 @@ type_getattro(PyTypeObject *type, PyObject *name) } /* Give up */ + if (!suppress_exception) { PyErr_Format(PyExc_AttributeError, "type object '%.50s' has no attribute '%U'", type->tp_name, name); + } return NULL; } +/* This is similar to PyObject_GenericGetAttr(), + but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ +PyObject * +type_getattro(PyTypeObject *type, PyObject *name) +{ + return _Py_type_getattro(type, name, 0); +} + static int type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) { From 480abbcc562ae6561c9b287591d1ab342686064b Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sat, 3 Dec 2022 23:52:47 +0100 Subject: [PATCH 2/2] make type_getattro static --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a54c9890aad854..c756a45dc8ad96 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4328,7 +4328,7 @@ _Py_type_getattro(PyTypeObject *type, PyObject *name, int suppress_exception) /* This is similar to PyObject_GenericGetAttr(), but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ -PyObject * +static PyObject * type_getattro(PyTypeObject *type, PyObject *name) { return _Py_type_getattro(type, name, 0);