@@ -1905,7 +1905,8 @@ class _TypingEllipsis:
1905
1905
1906
1906
_TYPING_INTERNALS = frozenset ({
1907
1907
'__parameters__' , '__orig_bases__' , '__orig_class__' ,
1908
- '_is_protocol' , '_is_runtime_protocol'
1908
+ '_is_protocol' , '_is_runtime_protocol' , '__protocol_attrs__' ,
1909
+ '__callable_proto_members_only__' ,
1909
1910
})
1910
1911
1911
1912
_SPECIAL_NAMES = frozenset ({
@@ -1935,11 +1936,6 @@ def _get_protocol_attrs(cls):
1935
1936
return attrs
1936
1937
1937
1938
1938
- def _is_callable_members_only (cls , protocol_attrs ):
1939
- # PEP 544 prohibits using issubclass() with protocols that have non-method members.
1940
- return all (callable (getattr (cls , attr , None )) for attr in protocol_attrs )
1941
-
1942
-
1943
1939
def _no_init_or_replace_init (self , * args , ** kwargs ):
1944
1940
cls = type (self )
1945
1941
@@ -2012,6 +2008,15 @@ def _lazy_load_getattr_static():
2012
2008
class _ProtocolMeta (ABCMeta ):
2013
2009
# This metaclass is really unfortunate and exists only because of
2014
2010
# the lack of __instancehook__.
2011
+ def __init__ (cls , * args , ** kwargs ):
2012
+ super ().__init__ (* args , ** kwargs )
2013
+ cls .__protocol_attrs__ = _get_protocol_attrs (cls )
2014
+ # PEP 544 prohibits using issubclass()
2015
+ # with protocols that have non-method members.
2016
+ cls .__callable_proto_members_only__ = all (
2017
+ callable (getattr (cls , attr , None )) for attr in cls .__protocol_attrs__
2018
+ )
2019
+
2015
2020
def __instancecheck__ (cls , instance ):
2016
2021
# We need this method for situations where attributes are
2017
2022
# assigned in __init__.
@@ -2029,7 +2034,7 @@ def __instancecheck__(cls, instance):
2029
2034
2030
2035
if is_protocol_cls :
2031
2036
getattr_static = _lazy_load_getattr_static ()
2032
- for attr in _get_protocol_attrs ( cls ) :
2037
+ for attr in cls . __protocol_attrs__ :
2033
2038
try :
2034
2039
val = getattr_static (instance , attr )
2035
2040
except AttributeError :
@@ -2095,9 +2100,7 @@ def _proto_hook(other):
2095
2100
raise TypeError ("Instance and class checks can only be used with"
2096
2101
" @runtime_checkable protocols" )
2097
2102
2098
- protocol_attrs = _get_protocol_attrs (cls )
2099
-
2100
- if not _is_callable_members_only (cls , protocol_attrs ):
2103
+ if not cls .__callable_proto_members_only__ :
2101
2104
if _allow_reckless_class_checks ():
2102
2105
return NotImplemented
2103
2106
raise TypeError ("Protocols with non-method members"
@@ -2107,7 +2110,7 @@ def _proto_hook(other):
2107
2110
raise TypeError ('issubclass() arg 1 must be a class' )
2108
2111
2109
2112
# Second, perform the actual structural compatibility check.
2110
- for attr in protocol_attrs :
2113
+ for attr in cls . __protocol_attrs__ :
2111
2114
for base in other .__mro__ :
2112
2115
# Check if the members appears in the class dictionary...
2113
2116
if attr in base .__dict__ :
0 commit comments