From a2c1657cab8daed6cf6236d67967372de7442d8b Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sun, 10 May 2026 04:52:52 +0200 Subject: [PATCH] gh-149436: Speed up inspect.getattr_static for the common-metaclass case (#149437) Consecutive MRO entries usually share their metaclass, so call _shadowed_dict at most once per distinct metaclass. --- Lib/inspect.py | 11 +++++++++-- .../2026-05-08-14-24-16.gh-issue-149436.dEV02X.rst | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-08-14-24-16.gh-issue-149436.dEV02X.rst diff --git a/Lib/inspect.py b/Lib/inspect.py index a96b3dc954ef0c..3e85625cd30263 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1709,9 +1709,13 @@ def _check_instance(obj, attr): def _check_class(klass, attr): + last_meta = None for entry in _static_getmro(klass): - if _shadowed_dict(type(entry)) is _sentinel and attr in entry.__dict__: - return entry.__dict__[attr] + meta = type(entry) + if meta is last_meta or _shadowed_dict(meta) is _sentinel: + last_meta = meta + if attr in entry.__dict__: + return entry.__dict__[attr] return _sentinel @@ -1743,6 +1747,9 @@ def _shadowed_dict(klass): # destroyed, and the dynamically created classes happen to be the only # objects that hold strong references to other objects that take up a # significant amount of memory. + # Fast path: `type` is the dominant caller; result is always _sentinel. + if klass is type: + return _sentinel return _shadowed_dict_from_weakref_mro_tuple( *[make_weakref(entry) for entry in _static_getmro(klass)] ) diff --git a/Misc/NEWS.d/next/Library/2026-05-08-14-24-16.gh-issue-149436.dEV02X.rst b/Misc/NEWS.d/next/Library/2026-05-08-14-24-16.gh-issue-149436.dEV02X.rst new file mode 100644 index 00000000000000..401cf044e1514f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-08-14-24-16.gh-issue-149436.dEV02X.rst @@ -0,0 +1 @@ +Improve performance of :meth:`inspect.getattr_static`.