8000 gh-102213: Optimize the performance of `__getattr__` (GH-103761) · python/cpython@59c27fa · GitHub
[go: up one dir, main page]

Skip to content

Commit 59c27fa

Browse files
sunmy2019Eclips4ambvwangxiang-hz
authored
gh-102213: Optimize the performance of __getattr__ (GH-103761)
Co-authored-by: Kirill <80244920+Eclips4@users.noreply.github.com> Co-authored-by: Łukasz Langa <lukasz@langa.pl> Co-authored-by: Xiang Wang <34048878+wangxiang-hz@users.noreply.github.com>
1 parent 487f55d commit 59c27fa

File tree

3 files changed

+28
-8
lines changed

3 files changed

+28
-8
lines changed

Lib/test/test_descr.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -5004,7 +5004,7 @@ class Child(Parent):
50045004
self.assertEqual(Parent.__subclasses__(), [])
50055005

50065006
def test_attr_raise_through_property(self):
5007-
# add test case for gh-103272
5007+
# test case for gh-103272
50085008
class A:
50095009
def __getattr__(self, name):
50105010
raise ValueError("FOO")
@@ -5016,6 +5016,19 @@ def foo(self):
50165016
with self.assertRaisesRegex(ValueError, "FOO"):
50175017
A().foo
50185018

5019+
# test case for gh-103551
5020+
class B:
5021+
@property
5022+
def __getattr__(self, name):
5023+
raise ValueError("FOO")
5024+
5025+
@property
5026+
def foo(self):
5027+
raise NotImplementedError("BAR")
5028+
5029+
with self.assertRaisesRegex(NotImplementedError, "BAR"):
5030+
B().foo
5031+
50195032

50205033
class DictProxyTests(unittest.TestCase):
50215034
def setUp(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix performance loss when accessing an object's attributes with ``__getattr__`` defined.

Objects/typeobject.c

+13-7
Original file line numberDiff line numberDiff line change
@@ -8306,17 +8306,23 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name)
83068306
if (getattribute == NULL ||
83078307
(Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) &&
83088308
((PyWrapperDescrObject *)getattribute)->d_wrapped ==
8309-
(void *)PyObject_GenericGetAttr))
8310-
res = PyObject_GenericGetAttr(self, name);
8311-
else {
8309+
(void *)PyObject_GenericGetAttr)) {
8310+
res = _PyObject_GenericGetAttrWithDict(self, name, NULL, 1);
8311+
/* if res == NULL with no exception set, then it must be an
8312+
AttributeError suppressed by us. */
8313+
if (res == NULL && !PyErr_Occurred()) {
8314+
res = call_attribute(self, getattr, name);
8315+
}
8316+
} else {
83128317
Py_INCREF(getattribute);
83138318
res = call_attribute(self, getattribute, name);
83148319
Py_DECREF(getattribute);
8320+
if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
8321+
PyErr_Clear();
8322+
res = call_attribute(self, getattr, name);
8323+
}
83158324
}
8316-
if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
8317-
PyErr_Clear();
8318-
res = call_attribute(self, getattr, name);
8319-
}
8325+
83208326
Py_DECREF(getattr);
83218327
return res;
83228328
}

0 commit comments

Comments
 (0)
0