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