From 1ef4b4bb60955a2727394860dd4d8ab2867a59b0 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sun, 4 Dec 2022 01:20:57 +0100 Subject: [PATCH 1/6] improve performance of hasattr for type objects --- Include/internal/pycore_typeobject.h | 4 ++++ Objects/object.c | 10 +++++++++- Objects/typeobject.c | 27 +++++++++++++++++++-------- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 71f3068900da31..e690488d36fe6e 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -80,6 +80,10 @@ extern static_builtin_state * _PyStaticType_GetState(PyTypeObject *); extern void _PyStaticType_ClearWeakRefs(PyTypeObject *type); extern void _PyStaticType_Dealloc(PyTypeObject *type); +PyObject * +_Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *flag); +PyObject * +_Py_type_getattro(PyTypeObject *type, PyObject *name); 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..ddeaa40100461f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -939,7 +939,15 @@ _PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result) } return 0; } - if (tp->tp_getattro != NULL) { + if (tp->tp_getattro == (getattrofunc)_Py_type_getattro) { + int flag = 0; + *result = _Py_type_getattro_impl((PyTypeObject*)v, name, &flag); + if (flag) { + // return 0 without having to clear the exception + return 0; + } + } + else if (tp->tp_getattro != NULL) { *result = (*tp->tp_getattro)(v, name); } else if (tp->tp_getattr != NULL) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ae80f5a8fd88e0..4aa25f8a613410 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4235,10 +4235,8 @@ is_dunder_name(PyObject *name) return 0; } -/* 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_impl(PyTypeObject *type, PyObject *name, int *suppress) { PyTypeObject *metatype = Py_TYPE(type); PyObject *meta_attribute, *attribute; @@ -4318,12 +4316,25 @@ type_getattro(PyTypeObject *type, PyObject *name) } /* Give up */ - PyErr_Format(PyExc_AttributeError, - "type object '%.50s' has no attribute '%U'", - type->tp_name, name); + if (suppress == NULL) { + PyErr_Format(PyExc_AttributeError, + "type object '%.50s' has no attribute '%U'", + type->tp_name, name); + } else { + // signal the caller we have not set an PyExc_AttributeError and gave up + *suppress = 1; + } return NULL; } +/* This is similar to PyObject_GenericGetAttr(), + but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ +PyObject * +_Py_type_getattro(PyTypeObject *type, PyObject *name) +{ + return _Py_type_getattro_impl(type, name, NULL); +} + static int type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) { @@ -4815,7 +4826,7 @@ PyTypeObject PyType_Type = { 0, /* tp_hash */ (ternaryfunc)type_call, /* tp_call */ 0, /* tp_str */ - (getattrofunc)type_getattro, /* tp_getattro */ + (getattrofunc)_Py_type_getattro, /* tp_getattro */ (setattrofunc)type_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | From 8f0f4728d5534f97d25542576e1ccafc060b757c Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sun, 4 Dec 2022 00:38:34 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2022-12-04-00-38-33.gh-issue-92216.CJXuWB.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-12-04-00-38-33.gh-issue-92216.CJXuWB.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-12-04-00-38-33.gh-issue-92216.CJXuWB.rst b/Misc/NEWS.d/next/Core and Builtins/2022-12-04-00-38-33.gh-issue-92216.CJXuWB.rst new file mode 100644 index 00000000000000..f7ef52d97c274a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-12-04-00-38-33.gh-issue-92216.CJXuWB.rst @@ -0,0 +1 @@ +Improve the performance of :func:`hasattr` for type objects with a missing attribute. From 9157e1b77423761662862665a5e1579c3365ab17 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sun, 18 Dec 2022 14:05:04 +0100 Subject: [PATCH 3/6] fix merge conflict --- Objects/typeobject.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b5a92cd4a2f164..3e10f3bbb395c4 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4218,25 +4218,6 @@ _PyType_LookupId(PyTypeObject *type, _Py_Identifier *name) return _PyType_Lookup(type, oname); } - -/* Check if the "readied" PyUnicode name - is a double-underscore special name. */ -static int -is_dunder_name(PyObject *name) -{ - Py_ssize_t length = PyUnicode_GET_LENGTH(name); - int kind = PyUnicode_KIND(name); - /* Special names contain at least "__x__" and are always ASCII. */ - if (length > 4 && kind == PyUnicode_1BYTE_KIND) { - const Py_UCS1 *characters = PyUnicode_1BYTE_DATA(name); - return ( - ((characters[length-2] == '_') && (characters[length-1] == '_')) && - ((characters[0] == '_') && (characters[1] == '_')) - ); - } - return 0; -} - /* This is similar to PyObject_GenericGetAttr(), but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ PyObject * From fa39a8e17c05e1d49ebaf91e38c18d959d27b2d2 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Fri, 23 Dec 2022 12:34:19 +0100 Subject: [PATCH 4/6] address review comments --- Include/internal/pycore_typeobject.h | 2 +- Objects/object.c | 6 +++--- Objects/typeobject.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index fef8f9dcdeca3a..9e6d1bb9ecb5b2 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -75,7 +75,7 @@ extern void _PyStaticType_ClearWeakRefs(PyTypeObject *type); extern void _PyStaticType_Dealloc(PyTypeObject *type); PyObject * -_Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *flag); +_Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *supress); PyObject * _Py_type_getattro(PyTypeObject *type, PyObject *name); diff --git a/Objects/object.c b/Objects/object.c index 82f31c5f6c4bcd..fae508cae3d693 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -940,9 +940,9 @@ _PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result) return 0; } if (tp->tp_getattro == (getattrofunc)_Py_type_getattro) { - int flag = 0; - *result = _Py_type_getattro_impl((PyTypeObject*)v, name, &flag); - if (flag) { + int supress_missing_attribute_exception = 0; + *result = _Py_type_getattro_impl((PyTypeObject*)v, name, &supress_missing_attribute_exception); + if (supress_missing_attribute_exception) { // return 0 without having to clear the exception return 0; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 3e10f3bbb395c4..f8dc170277918a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4811,7 +4811,7 @@ PyTypeObject PyType_Type = { 0, /* tp_hash */ (ternaryfunc)type_call, /* tp_call */ 0, /* tp_str */ - (getattrofunc)_Py_type_getattro, /* tp_getattro */ + (getattrofunc)_Py_type_getattro, /* tp_getattro */ (setattrofunc)type_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | From ed3e02349433c0d702e3e0185826274138755be0 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Fri, 23 Dec 2022 14:15:16 +0100 Subject: [PATCH 5/6] add docstring --- Include/internal/pycore_typeobject.h | 2 +- Objects/typeobject.c | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 9e6d1bb9ecb5b2..4d705740a9a62b 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -75,7 +75,7 @@ extern void _PyStaticType_ClearWeakRefs(PyTypeObject *type); extern void _PyStaticType_Dealloc(PyTypeObject *type); PyObject * -_Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *supress); +_Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *suppress_missing_attribute); PyObject * _Py_type_getattro(PyTypeObject *type, PyObject *name); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f8dc170277918a..90ec9a95103720 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4219,9 +4219,19 @@ _PyType_LookupId(PyTypeObject *type, _Py_Identifier *name) } /* This is similar to PyObject_GenericGetAttr(), - but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ + but uses _PyType_Lookup() instead of just looking in type->tp_dict. + + The argument suppress_missing_attribute is used to provide a + fast path for hasattr. The modes are: + + * NULL: do not suppress the exception + * Non-zero pointer: suppress the PyExc_AttributeError and set + *suppress_missing_attribute to 1 to signal we are returning NULL while + having suppressed the exception (other exceptions are not suppressed) + + */ PyObject * -_Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *suppress) +_Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int * suppress_missing_attribute) { PyTypeObject *metatype = Py_TYPE(type); PyObject *meta_attribute, *attribute; @@ -4301,13 +4311,13 @@ _Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *suppress) } /* Give up */ - if (suppress == NULL) { + if (suppress_missing_attribute == NULL) { PyErr_Format(PyExc_AttributeError, "type object '%.50s' has no attribute '%U'", type->tp_name, name); } else { // signal the caller we have not set an PyExc_AttributeError and gave up - *suppress = 1; + *suppress_missing_attribute = 1; } return NULL; } From 1d15a74ab04f5cad23b05229c39d19a379fb1711 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Fri, 23 Dec 2022 14:18:01 +0100 Subject: [PATCH 6/6] update docstring --- Objects/typeobject.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 90ec9a95103720..16b1a3035d56f1 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4222,12 +4222,12 @@ _PyType_LookupId(PyTypeObject *type, _Py_Identifier *name) but uses _PyType_Lookup() instead of just looking in type->tp_dict. The argument suppress_missing_attribute is used to provide a - fast path for hasattr. The modes are: + fast path for hasattr. The possible values are: * NULL: do not suppress the exception - * Non-zero pointer: suppress the PyExc_AttributeError and set - *suppress_missing_attribute to 1 to signal we are returning NULL while - having suppressed the exception (other exceptions are not suppressed) + * Non-zero pointer: suppress the PyExc_AttributeError and + set *suppress_missing_attribute to 1 to signal we are returning NULL while + having suppressed the exception (other exceptions are not suppressed) */ PyObject * pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy