@@ -1398,8 +1398,29 @@ def _is_callable_members_only(cls):
1398
1398
return all (callable (getattr (cls , attr , None )) for attr in _get_protocol_attrs (cls ))
1399
1399
1400
1400
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
+
1403
1424
1404
1425
def _caller (depth = 1 , default = '__main__' ):
1405
1426
try :
@@ -1542,15 +1563,6 @@ def _proto_hook(other):
1542
1563
1543
1564
# We have nothing more to do for non-protocols...
1544
1565
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__
1554
1566
return
1555
1567
1556
1568
# ... otherwise check consistency of bases, and prohibit instantiation.
@@ -1561,7 +1573,7 @@ def _proto_hook(other):
1561
1573
issubclass (base , Generic ) and base ._is_protocol ):
1562
1574
raise TypeError ('Protocols can only inherit from other'
1563
1575
' protocols, got %r' % base )
1564
- cls .__init__ = _no_init
1576
+ cls .__init__ = _no_init_or_replace_init
1565
1577
1566
1578
1567
1579
class _AnnotatedAlias (_GenericAlias , _root = True ):
0 commit comments