[Python-Dev] PEP487: Simpler customization of class creation

Nick Coghlan ncoghlan at gmail.com
Thu Jul 28 10:22:49 EDT 2016


On 29 July 2016 at 00:06, Joao S. O. Bueno <jsbueno at python.org.br> wrote:
> 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)

The class decorator approach looks like this:

    def run_init_subclass(cls, **kwds):
        cls.__init_subclass__(**kwds)

However, it's not the right way to do it, as it means super(cls,
cls).__init_subclass__(**kwds) will get called a second time (since
the class machinery will have already done it implicitly before
invoking the class decorators). If the parent class methods are
idempotent then calling them again won't matter, but if you're
supplying extra keyword arguments, you'd need to specify them in both
the decorator call *and* the class header. (I didn't actually realise
this problem until writing the earlier email, so I'll probably tweak
that part of the PEP to be more explicit about this aspect)

So the simplest approach if you want "this class *and* all its
descendants" behaviour is to adhere to the "strict subclasses only"
requirement, and put the __init_subclass__ implementation in a base
class, even if that means creating an additional mixin just to hold
it.

If that recommended approach isn't acceptable for some reason, then
the decorator-centric alternative would be to instead write it this
way:

    def decorate_class(cls, **kwds):
        ...

    @decorate_class
    class MyClass:
        def __init_subclass__(cls, **kwds):
            super().__init_subclass__(**kwds)
            decorate_class(cls)

So the decorator gets defined outside the class, applied explicitly to
the base class, and then the __init_subclass__ hook applies it
implicitly to all subclasses.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-Dev mailing list