{{ message }}
gh-103193: Use LBYL idioms rather than EAFP in inspect.getattr_static#103318
Merged
AlexWaygood merged 1 commit intopython:mainfrom Apr 6, 2023
Merged
gh-103193: Use LBYL idioms rather than EAFP in inspect.getattr_static#103318AlexWaygood merged 1 commit intopython:mainfrom
inspect.getattr_static#103318AlexWaygood merged 1 commit intopython:mainfrom
Conversation
Member
Author
carljm
approved these changes
Apr 6, 2023
Member
carljm
left a comment
There was a problem hiding this comment.
It's less idiomatic code, but I think it's worth it for the very significant performance improvement on runtime protocol isinstance checking with many attributes.
I assume you've checked the performance of using .get(...) and it's worse?
Member
Author
Hmm I haven't, actually -- not sure how you'd use |
Member
Author
|
Oh I think I see what you mean. Trying it out now. |
Member
Author
|
Yeah, I tried out doing this instead (diff is relative to my current patch, not to diff --git a/Lib/inspect.py b/Lib/inspect.py
index a317f0ca74..7fcaa13750 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1787,8 +1787,10 @@ def _check_instance(obj, attr):
def _check_class(klass, attr):
for entry in _static_getmro(klass):
- if _shadowed_dict(type(entry)) is _sentinel and attr in entry.__dict__:
- return entry.__dict__[attr]
+ if _shadowed_dict(type(entry)) is _sentinel:
+ ret = entry.__dict__.get(attr, _sentinel)
+ if ret is not _sentinel:
+ return ret
return _sentinel
def _is_type(obj):
@@ -1800,13 +1802,13 @@ def _is_type(obj):
def _shadowed_dict(klass):
for entry in _static_getmro(klass):
- dunder_dict = _get_dunder_dict_of_class(entry)
- if '__dict__' in dunder_dict:
- class_dict = dunder_dict['__dict__']
- if not (type(class_dict) is types.GetSetDescriptorType and
- class_dict.__name__ == "__dict__" and
- class_dict.__objclass__ is entry):
- return class_dict
+ class_dict = _get_dunder_dict_of_class(entry).get('__dict__', _sentinel)
+ if class_dict is not _sentinel and not (
+ type(class_dict) is types.GetSetDescriptorType
+ and class_dict.__name__ == "__dict__"
+ and class_dict.__objclass__ is entry
+ ):
+ return class_dict
return _sentinel
def getattr_static(obj, attr, default=_sentinel):
@@ -1845,11 +1847,10 @@ def getattr_static(obj, attr, default=_sentinel):
if obj is klass:
# for types we check the metaclass too
for entry in _static_getmro(type(klass)):
- if (
- _shadowed_dict(type(entry)) is _sentinel
- and attr in entry.__dict__
- ):
- return entry.__dict__[attr]
+ if _shadowed_dict(type(entry)) is _sentinel:
+ ret = entry.__dict__.get(attr, _sentinel)
+ if ret is not _sentinel:
+ return ret@carljm is that the kind of thing you were talking about? :) |
Member
Author
This was referenced Apr 6, 2023
warsaw
pushed a commit
to warsaw/cpython
that referenced
this pull request
Apr 11, 2023
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

This PR significantly speeds up
inspect.getattr_static()and, as a result,isinstance()checks against runtime-checkable protocols.Here are benchmark results on main using @sobolevn's benchmark script from #103193 (comment):
And here are the benchmark results with this PR:
A result of this optimisation is that the following
isinstance()call becomes around 1.5x faster:inspect.getattr_static#103193