mirror of https://github.com/python/cpython
gh-104066: Improve performance of hasattr for module objects (#104063)
This commit is contained in:
parent
c9ecd3ee75
commit
fdcb49c36b
|
@ -36,6 +36,9 @@ static inline PyObject* _PyModule_GetDict(PyObject *mod) {
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject* _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress);
|
||||||
|
PyObject* _Py_module_getattro(PyModuleObject *m, PyObject *name);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve the performance of :func:`hasattr` for module objects with a missing
|
||||||
|
attribute.
|
|
@ -702,7 +702,11 @@ int
|
||||||
_PyModuleSpec_IsInitializing(PyObject *spec)
|
_PyModuleSpec_IsInitializing(PyObject *spec)
|
||||||
{
|
{
|
||||||
if (spec != NULL) {
|
if (spec != NULL) {
|
||||||
PyObject *value = PyObject_GetAttr(spec, &_Py_ID(_initializing));
|
PyObject *value;
|
||||||
|
int ok = _PyObject_LookupAttr(spec, &_Py_ID(_initializing), &value);
|
||||||
|
if (ok == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (value != NULL) {
|
if (value != NULL) {
|
||||||
int initializing = PyObject_IsTrue(value);
|
int initializing = PyObject_IsTrue(value);
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
|
@ -738,19 +742,37 @@ _PyModuleSpec_IsUninitializedSubmodule(PyObject *spec, PyObject *name)
|
||||||
return is_uninitialized;
|
return is_uninitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
PyObject*
|
||||||
module_getattro(PyModuleObject *m, PyObject *name)
|
_Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
|
||||||
{
|
{
|
||||||
|
// When suppress=1, this function suppresses AttributeError.
|
||||||
PyObject *attr, *mod_name, *getattr;
|
PyObject *attr, *mod_name, *getattr;
|
||||||
attr = PyObject_GenericGetAttr((PyObject *)m, name);
|
attr = _PyObject_GenericGetAttrWithDict((PyObject *)m, name, NULL, suppress);
|
||||||
if (attr || !PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
if (attr) {
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
if (suppress == 1) {
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
// pass up non-AttributeError exception
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||||
|
// pass up non-AttributeError exception
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
}
|
||||||
assert(m->md_dict != NULL);
|
assert(m->md_dict != NULL);
|
||||||
getattr = PyDict_GetItemWithError(m->md_dict, &_Py_ID(__getattr__));
|
getattr = PyDict_GetItemWithError(m->md_dict, &_Py_ID(__getattr__));
|
||||||
if (getattr) {
|
if (getattr) {
|
||||||
return PyObject_CallOneArg(getattr, name);
|
PyObject *result = PyObject_CallOneArg(getattr, name);
|
||||||
|
if (result == NULL && suppress == 1 && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||||
|
// suppress AttributeError
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -763,6 +785,7 @@ module_getattro(PyModuleObject *m, PyObject *name)
|
||||||
Py_DECREF(mod_name);
|
Py_DECREF(mod_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (suppress != 1) {
|
||||||
Py_XINCREF(spec);
|
Py_XINCREF(spec);
|
||||||
if (_PyModuleSpec_IsInitializing(spec)) {
|
if (_PyModuleSpec_IsInitializing(spec)) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
|
@ -783,17 +806,27 @@ module_getattro(PyModuleObject *m, PyObject *name)
|
||||||
mod_name, name);
|
mod_name, name);
|
||||||
}
|
}
|
||||||
Py_XDECREF(spec);
|
Py_XDECREF(spec);
|
||||||
|
}
|
||||||
Py_DECREF(mod_name);
|
Py_DECREF(mod_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (PyErr_Occurred()) {
|
else if (PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (suppress != 1) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
"module has no attribute '%U'", name);
|
"module has no attribute '%U'", name);
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject*
|
||||||
|
_Py_module_getattro(PyModuleObject *m, PyObject *name)
|
||||||
|
{
|
||||||
|
return _Py_module_getattro_impl(m, name, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
module_traverse(PyModuleObject *m, visitproc visit, void *arg)
|
module_traverse(PyModuleObject *m, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
|
@ -951,7 +984,7 @@ PyTypeObject PyModule_Type = {
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
(getattrofunc)module_getattro, /* tp_getattro */
|
(getattrofunc)_Py_module_getattro, /* tp_getattro */
|
||||||
PyObject_GenericSetAttr, /* tp_setattro */
|
PyObject_GenericSetAttr, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||||
|
|
|
@ -1085,6 +1085,17 @@ _PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (tp->tp_getattro == (getattrofunc)_Py_module_getattro) {
|
||||||
|
// optimization: suppress attribute error from module getattro method
|
||||||
|
*result = _Py_module_getattro_impl((PyModuleObject*)v, name, 1);
|
||||||
|
if (*result != NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
else if (tp->tp_getattro != NULL) {
|
else if (tp->tp_getattro != NULL) {
|
||||||
*result = (*tp->tp_getattro)(v, name);
|
*result = (*tp->tp_getattro)(v, name);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue