Skip to content

Commit

Permalink
pythongh-74690: Optimise isinstance() and issubclass() calls agai…
Browse files Browse the repository at this point in the history
…nst runtime-checkable protocols by avoiding costly `super()` calls (python#112708)
  • Loading branch information
AlexWaygood authored and aisk committed Feb 11, 2024
1 parent da78577 commit 78c8faf
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 3 deletions.
14 changes: 11 additions & 3 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1782,6 +1782,14 @@ def _pickle_pskwargs(pskwargs):
del _pickle_psargs, _pickle_pskwargs


# Preload these once, as globals, as a micro-optimisation.
# This makes a significant difference to the time it takes
# to do `isinstance()`/`issubclass()` checks
# against runtime-checkable protocols with only one callable member.
_abc_instancecheck = ABCMeta.__instancecheck__
_abc_subclasscheck = ABCMeta.__subclasscheck__


class _ProtocolMeta(ABCMeta):
# This metaclass is somewhat unfortunate,
# but is necessary for several reasons...
Expand Down Expand Up @@ -1841,7 +1849,7 @@ def __subclasscheck__(cls, other):
"Instance and class checks can only be used with "
"@runtime_checkable protocols"
)
return super().__subclasscheck__(other)
return _abc_subclasscheck(cls, other)

def __instancecheck__(cls, instance):
# We need this method for situations where attributes are
Expand All @@ -1850,7 +1858,7 @@ def __instancecheck__(cls, instance):
return type.__instancecheck__(cls, instance)
if not getattr(cls, "_is_protocol", False):
# i.e., it's a concrete subclass of a protocol
return super().__instancecheck__(instance)
return _abc_instancecheck(cls, instance)

if (
not getattr(cls, '_is_runtime_protocol', False) and
Expand All @@ -1859,7 +1867,7 @@ def __instancecheck__(cls, instance):
raise TypeError("Instance and class checks can only be used with"
" @runtime_checkable protocols")

if super().__instancecheck__(instance):
if _abc_instancecheck(cls, instance):
return True

getattr_static = _lazy_load_getattr_static()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Speedup :func:`isinstance` checks by roughly 20% for
:func:`runtime-checkable protocols <typing.runtime_checkable>`
that only have one callable member.
Speedup :func:`issubclass` checks for these protocols by roughly 10%.
Patch by Alex Waygood.

0 comments on commit 78c8faf

Please sign in to comment.