On 28 July 2016 at 10:53, Nick Coghlan <ncogh...@gmail.com> wrote: > On 28 July 2016 at 23:12, Joao S. O. Bueno <jsbu...@python.org.br> wrote: >> Although I know it is not straightforward to implement (as the >> "metaclass" parameter is not passed to the metaclass __new__ or >> __init__), wouldn't it make sense to make it be passed to >> __init_subclass__ just like all other keywords? (the default >> __init_subclass__ then could swallow it, if it reaches there). >> >> I am putting the question now, because it is a matter of "now" or >> "never" - I can see it can does make sense if it is not passed down. > > It would complicate the implementation, and has the potential to be > confusing (since the explicit metaclass hint and the actual metaclass > aren't guaranteed to be the same), so I don't think it makes sense to > pass it down. I'll make sure we note it in the documentation for the > new protocol method, though. > >> Anyway, do you have any remarks on the first issue I raised? About >> __init_subclass__ being called in the class it is defined in, not just >> on it's descendant subclasses? > > That's already covered in the PEP: > https://www.python.org/dev/peps/pep-0487/#calling-the-hook-on-the-class-itself > > We want to make it easy for mixin classes to use __init_subclass__ to > define "required attributes" on subclasses, and that's straightforward > with the current definition: > > class MyMixin: > def __init_subclass__(cls, **kwargs): > super().__init_subclass__(**kwargs) > if not hasattr(cls, "mixin_required_attribute"): > raise TypeError(f"Subclasses of {__class__} must > define a 'mixin_required_attribute' attribute") > > If you actually do want the init_subclass__ method to also run on the > "base" class, then you'll need to tweak the class hierarchy a bit to > look like: > > class _PrivateInitBase: > def __init_subclass__(cls, **kwargs): > super().__init_subclass__(**kwargs) > ... > > def MyOriginalClass(_PrivateInitBase): > ... > > (You don't want to call __init_subclass__ from a class decorator, as > that would call any parent __init_subclass__ implementations a second > time) > > By contrast, when we had the default the other way around, opting > *out* of self-application required boilerplate inside of > __init_subclass__ to special case the situation where "cls is > __class__": > > class MyMixin: > def __init_subclass__(cls, **kwargs): > super().__init_subclass__(**kwargs) > if cls is __class__: > return # Don't init the base class > if not getattr(cls, "mixin_required_attribute", None) is None: > raise TypeError(f"Subclasses of {__class__} must > define a non-None 'mixin_required_attribute' attribute") > > This raises exciting new opportunities for subtle bugs, like bailing > out *before* calling the parent __init_subclass__ method, and then > figure out that a later error from an apparently unrelated method is > because your __init_subclass__ implementation is buggy. > > There's still an opportunity for bugs with the current design decision > (folks expecting __init_subclass__ to be called on the class defining > it when that isn't the case), but they should be relatively shallow > ones, and once people learn the rule that __init_subclass__ is only > called on *strict* subclasses, it's a pretty easy behaviour to > remember.
Thanks for the extensive reasoning. Maybe then adding a `run_init_subclass` class decorator on the stdlib to go along with the pep? It should be a two liner that would avoid boiler plate done wrong - but more important than thatm is that it being documented alog with the __init_sublass__ method will make it more obvious it is not run where it is defined. (I had missed it in the PEP text and just understood that part when re-reading the PEP after being surprised) js -><- > > Cheers, > Nick. > > -- > Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com