Tim Pozza
Tim Pozza

Reputation: 548

should I be afraid of the way __init_subclass__ kicks off?

I'm using init_subclass in a project, and I sort of balked when I ran into the built in method kicking off when the code first runs in the interpreter -- without being directly referenced via instantiation of the containing class or the sub-classes it enumerates.

Can someone tell me what's going on, and point me to any examples of its safe use?

class Timer():

    def __init__(self):
        pass

    def __init_subclass__(cls):
        print('Runner.', cls)
        print('Timer Dictionary :', Timer.__dict__.keys())
        # print(Timer.__init_subclass__()) # Forbidden fruit...
        pass

class Event(Timer):
    print("I'll take my own bathroom selfies...thanks anyway.")

    def __init__(self):
        print('This is nice, meeting on a real date.')

if __name__ == '__main__': # a good place for a breakpoint
        date = Event()
        date

Edit --------------------------------------------------

Based on the explanations received, original code was retooled into something useful.

class Timer():

    subclasses = {}

    def __init__(self):
        pass

    def __init_subclass__(cls, **kwargs):
        print('Runner.', cls)
        print('Timer Dictionary :', Timer.__dict__.keys())
        # print(Timer.__init_subclass__()) # Forbidden fruit...
        super().__init_subclass__(**kwargs)
        cls.subclasses[cls] = []


class Event(Timer):
    print("I'll take my own bathroom selfies...thanks anyway.")

    def __init__(self):
        print('This is nice, meeting on a real date.')
        if self.__class__ in super().subclasses:
            # get the index and link the two
            super().subclasses[self.__class__].append(self)

if __name__ == '__main__': # a good place for a breakpoint
    date = Event()
    date
    duty = Event()
    duty
    print(Timer.subclasses)

Upvotes: 1

Views: 2475

Answers (1)

Pedro Silva
Pedro Silva

Reputation: 4710

Here's a minimal example:

class Super():
    def __init_subclass__(cls):
        print(cls)

class Sub(Super):
    pass

Running this:

$ python test.py
<class '__main__.Sub'>

Why is that? According to Python's data model docs:

Whenever a class inherits from another class, init_subclass is called on that class.

Sub inherits from Super, so Super.__init_subclass__() gets called.

Specifically, type_new() invokes init_subclass in the cpython implementation.

The rationale is detailed in PEP 487.

Upvotes: 6

Related Questions