Skip to content

Commit c718ab9

Browse files
authored
gh-74690: Optimise isinstance() and issubclass() calls against runtime-checkable protocols by avoiding costly super() calls (#112708)
1 parent 9560e0d commit c718ab9

File tree

2 files changed

+16
-3
lines changed

2 files changed

+16
-3
lines changed

Lib/typing.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -1782,6 +1782,14 @@ def _pickle_pskwargs(pskwargs):
17821782
del _pickle_psargs, _pickle_pskwargs
17831783

17841784

1785+
# Preload these once, as globals, as a micro-optimisation.
1786+
# This makes a significant difference to the time it takes
1787+
# to do `isinstance()`/`issubclass()` checks
1788+
# against runtime-checkable protocols with only one callable member.
1789+
_abc_instancecheck = ABCMeta.__instancecheck__
1790+
_abc_subclasscheck = ABCMeta.__subclasscheck__
1791+
1792+
17851793
class _ProtocolMeta(ABCMeta):
17861794
# This metaclass is somewhat unfortunate,
17871795
# but is necessary for several reasons...
@@ -1841,7 +1849,7 @@ def __subclasscheck__(cls, other):
18411849
"Instance and class checks can only be used with "
18421850
"@runtime_checkable protocols"
18431851
)
1844-
return super().__subclasscheck__(other)
1852+
return _abc_subclasscheck(cls, other)
18451853

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

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

1862-
if super().__instancecheck__(instance):
1870+
if _abc_instancecheck(cls, instance):
18631871
return True
18641872

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

0 commit comments

Comments
 (0)