@@ -1079,8 +1079,29 @@ def _is_callable_members_only(cls):
10791079 return all (callable (getattr (cls , attr , None )) for attr in _get_protocol_attrs (cls ))
10801080
10811081
1082- def _no_init (self , * args , ** kwargs ):
1083- raise TypeError ('Protocols cannot be instantiated' )
1082+ def _no_init_or_replace_init (self , * args , ** kwargs ):
1083+ cls = type (self )
1084+
1085+ if cls ._is_protocol :
1086+ raise TypeError ('Protocols cannot be instantiated' )
1087+
1088+ # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1089+ # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1090+ # searches for a proper new `__init__` in the MRO. The new `__init__`
1091+ # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1092+ # instantiation of the protocol subclass will thus use the new
1093+ # `__init__` and no longer call `_no_init_or_replace_init`.
1094+ for base in cls .__mro__ :
1095+ init = base .__dict__ .get ('__init__' , _no_init_or_replace_init )
1096+ if init is not _no_init_or_replace_init :
1097+ cls .__init__ = init
1098+ break
1099+ else :
1100+ # should not happen
1101+ cls .__init__ = object .__init__
1102+
1103+ cls .__init__ (self , * args , ** kwargs )
1104+
10841105
10851106
10861107def _allow_reckless_class_cheks ():
@@ -1209,15 +1230,6 @@ def _proto_hook(other):
12091230
12101231 # We have nothing more to do for non-protocols...
12111232 if not cls ._is_protocol :
1212- if cls .__init__ == _no_init :
1213- for base in cls .__mro__ :
1214- init = base .__dict__ .get ('__init__' , _no_init )
1215- if init != _no_init :
1216- cls .__init__ = init
1217- break
1218- else :
1219- # should not happen
1220- cls .__init__ = object .__init__
12211233 return
12221234
12231235 # ... otherwise check consistency of bases, and prohibit instantiation.
@@ -1228,7 +1240,7 @@ def _proto_hook(other):
12281240 issubclass (base , Generic ) and base ._is_protocol ):
12291241 raise TypeError ('Protocols can only inherit from other'
12301242 ' protocols, got %r' % base )
1231- cls .__init__ = _no_init
1243+ cls .__init__ = _no_init_or_replace_init
12321244
12331245
12341246class _AnnotatedAlias (_GenericAlias , _root = True ):
0 commit comments