Skip to content

Commit f15c64a

Browse files
committed
pythongh-74690: typing: Cache results of _get_protocol_attrs and _callable_member_only
1 parent d97aef8 commit f15c64a

File tree

1 file changed

+12
-11
lines changed

1 file changed

+12
-11
lines changed

Lib/typing.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1935,9 +1935,9 @@ def _get_protocol_attrs(cls):
19351935
return attrs
19361936

19371937

1938-
def _is_callable_members_only(cls, protocol_attrs):
1938+
def _is_callable_members_only(cls):
19391939
# 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)
1940+
return all(callable(getattr(cls, attr, None)) for attr in cls.__protocol_attrs__)
19411941

19421942

19431943
def _no_init_or_replace_init(self, *args, **kwargs):
@@ -2016,20 +2016,19 @@ def __instancecheck__(cls, instance):
20162016
if not is_protocol_cls and issubclass(instance.__class__, cls):
20172017
return True
20182018

2019-
protocol_attrs = _get_protocol_attrs(cls)
2019+
if not hasattr(cls, "__protocol_attrs__"):
2020+
cls.__protocol_attrs__ = _get_protocol_attrs(cls)
2021+
cls.__callable_proto_members_only__ = _is_callable_members_only(cls)
20202022

2021-
if (
2022-
_is_callable_members_only(cls, protocol_attrs)
2023-
and issubclass(instance.__class__, cls)
2024-
):
2023+
if cls.__callable_proto_members_only__ and issubclass(instance.__class__, cls):
20252024
return True
20262025

20272026
if is_protocol_cls:
20282027
if all(hasattr(instance, attr) and
20292028
# All *methods* can be blocked by setting them to None.
20302029
(not callable(getattr(cls, attr, None)) or
20312030
getattr(instance, attr) is not None)
2032-
for attr in protocol_attrs):
2031+
for attr in cls.__protocol_attrs__):
20332032
return True
20342033
return super().__instancecheck__(instance)
20352034

@@ -2087,9 +2086,11 @@ def _proto_hook(other):
20872086
raise TypeError("Instance and class checks can only be used with"
20882087
" @runtime_checkable protocols")
20892088

2090-
protocol_attrs = _get_protocol_attrs(cls)
2089+
if not hasattr(cls, "__protocol_attrs__"):
2090+
cls.__protocol_attrs__ = _get_protocol_attrs(cls)
2091+
cls.__callable_proto_members_only__ = _is_callable_members_only(cls)
20912092

2092-
if not _is_callable_members_only(cls, protocol_attrs):
2093+
if not cls.__callable_proto_members_only__ :
20932094
if _allow_reckless_class_checks():
20942095
return NotImplemented
20952096
raise TypeError("Protocols with non-method members"
@@ -2099,7 +2100,7 @@ def _proto_hook(other):
20992100
raise TypeError('issubclass() arg 1 must be a class')
21002101

21012102
# Second, perform the actual structural compatibility check.
2102-
for attr in protocol_attrs:
2103+
for attr in cls.__protocol_attrs__:
21032104
for base in other.__mro__:
21042105
# Check if the members appears in the class dictionary...
21052106
if attr in base.__dict__:

0 commit comments

Comments
 (0)