@@ -1398,8 +1398,29 @@ def _is_callable_members_only(cls):
13981398 return all (callable (getattr (cls , attr , None )) for attr in _get_protocol_attrs (cls ))
13991399
14001400
1401- def _no_init (self , * args , ** kwargs ):
1402- raise TypeError ('Protocols cannot be instantiated' )
1401+ def _no_init_or_replace_init (self , * args , ** kwargs ):
1402+ cls = type (self )
1403+
1404+ if cls ._is_protocol :
1405+ raise TypeError ('Protocols cannot be instantiated' )
1406+
1407+ # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1408+ # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1409+ # searches for a proper new `__init__` in the MRO. The new `__init__`
1410+ # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1411+ # instantiation of the protocol subclass will thus use the new
1412+ # `__init__` and no longer call `_no_init_or_replace_init`.
1413+ for base in cls .__mro__ :
1414+ init = base .__dict__ .get ('__init__' , _no_init_or_replace_init )
1415+ if init is not _no_init_or_replace_init :
1416+ cls .__init__ = init
1417+ break
1418+ else :
1419+ # should not happen
1420+ cls .__init__ = object .__init__
1421+
1422+ cls .__init__ (self , * args , ** kwargs )
1423+
14031424
14041425def _caller (depth = 1 , default = '__main__' ):
14051426 try :
@@ -1542,15 +1563,6 @@ def _proto_hook(other):
15421563
15431564 # We have nothing more to do for non-protocols...
15441565 if not cls ._is_protocol :
1545- if cls .__init__ == _no_init :
1546- for base in cls .__mro__ :
1547- init = base .__dict__ .get ('__init__' , _no_init )
1548- if init != _no_init :
1549- cls .__init__ = init
1550- break
1551- else :
1552- # should not happen
1553- cls .__init__ = object .__init__
15541566 return
15551567
15561568 # ... otherwise check consistency of bases, and prohibit instantiation.
@@ -1561,7 +1573,7 @@ def _proto_hook(other):
15611573 issubclass (base , Generic ) and base ._is_protocol ):
15621574 raise TypeError ('Protocols can only inherit from other'
15631575 ' protocols, got %r' % base )
1564- cls .__init__ = _no_init
1576+ cls .__init__ = _no_init_or_replace_init
15651577
15661578
15671579class _AnnotatedAlias (_GenericAlias , _root = True ):
0 commit comments