Simpler Customization of Class Creation, next round

Hello everybody, recently I posted PEP 487, a simpler customization of class creation. For newcomers: I propose the introduction of a __init_subclass__ classmethod which initializes subclasses of a class, simplifying what metaclasses can already do. It took me a while to digest all the ideas from the list here, but well, we're not in a hurry. So, I updated PEP 487, and pushed the changes to github at https://github.com/tecki/peps/commits/master I applied the following changes: PEP 487 contained the possibility to set a namespace for subclasses. The most important usecase for this feature would be to have an OrderedDict as the class definition namespace. As Eric Snow pointed out, that will be soon standard anyways, so I took out this feature from the PEP. The implementation on PyPI now just uses an OrderedDict as a namespace, anticipating the expected changes to CPython. I also did some reading on possible usecases for PEP 487, so that it actually may be used by someone. Some Traits-like thing is a standard usecase, so I looked especially at IPython's traitlets, which are a simple example of that usecase. Currently traitlets use both __new__ and __init__ of a metaclass. So I tried to also introduce a __new_subclass__ the same way I introduced __init_subclass__. This turned out much harder than I thought, actually impossible, because it is type.__new__ that sets the method resolution order, so making super() work in a __new_subclass__ hook is a chicken-egg problem: we need the MRO to find the next base class to call, but the most basic base class is the one creating the MRO. Nick, how did you solve that problem in PEP 422? Anyhow, I think that traitlets can also be written just using __init_subclass__. There is just this weird hint in the docs that you should use __new__ for metaclasses, not __init__, a hint I never understood as the reasons when to use __new__ or __init__ are precisely the same for normal classes and metaclasses. So I think we don't miss out much when not having __new_subclass__. I also updated the implementation of PEP 487, it's still at https://pypi.python.org/pypi/metaclass Greetings Martin

On Tue, Mar 17, 2015 at 9:55 AM, Martin Teichmann <lkb.teichmann@gmail.com> wrote:
class Meta(type): def __init__(cls, ...): ... class X(metaclass=Meta): ... and class Base: def __init_subclass__(cls, ...): ... class X(Base): ... The only difference I see is relative to metaclass conflcts. You still have to define an extra type (Meta or Base) to get the effect. Furthermore, there would now be second (but indistinct) way of initializing a subclass, making the "meta" class situation even murkier. If the only benefit is the mitigation of metaclass conflicts then perhaps such conflicts should be addressed directly and we should not add __init_subclass__. From other threads it sounds like we should be able to solve metaclass conflicts one way or another. Another thing I'm unclear on is what will happen if a subclass were to define its own __init_subclass__? -eric

On 6 April 2015 at 11:43, Eric Snow <ericsnowcurrently@gmail.com> wrote:
The main intended readability/maintainability benefit is from the perspective of more clearly distinguishing the "customises subclass initialisation" case from the "customises runtime behaviour of subclasses" case. A full custom metaclass doesn't provide any indication of the scope of impact, while __init_subclass__ more clearly indicates that there's no persistent effects on behaviour post-subclass creation.
Another thing I'm unclear on is what will happen if a subclass were to define its own __init_subclass__?
Same thing that happens with any other class method - chaining to the base class implementation would be in the hands of the subclass author via super(). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Tue, Mar 17, 2015 at 9:55 AM, Martin Teichmann <lkb.teichmann@gmail.com> wrote:
class Meta(type): def __init__(cls, ...): ... class X(metaclass=Meta): ... and class Base: def __init_subclass__(cls, ...): ... class X(Base): ... The only difference I see is relative to metaclass conflcts. You still have to define an extra type (Meta or Base) to get the effect. Furthermore, there would now be second (but indistinct) way of initializing a subclass, making the "meta" class situation even murkier. If the only benefit is the mitigation of metaclass conflicts then perhaps such conflicts should be addressed directly and we should not add __init_subclass__. From other threads it sounds like we should be able to solve metaclass conflicts one way or another. Another thing I'm unclear on is what will happen if a subclass were to define its own __init_subclass__? -eric

On 6 April 2015 at 11:43, Eric Snow <ericsnowcurrently@gmail.com> wrote:
The main intended readability/maintainability benefit is from the perspective of more clearly distinguishing the "customises subclass initialisation" case from the "customises runtime behaviour of subclasses" case. A full custom metaclass doesn't provide any indication of the scope of impact, while __init_subclass__ more clearly indicates that there's no persistent effects on behaviour post-subclass creation.
Another thing I'm unclear on is what will happen if a subclass were to define its own __init_subclass__?
Same thing that happens with any other class method - chaining to the base class implementation would be in the hands of the subclass author via super(). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
participants (3)
-
Eric Snow
-
Martin Teichmann
-
Nick Coghlan