Is there any method like __init_subclass__() befor

2019-09-19 10:28发布

问题:

When I read Python Cookbook 3Edition recipe 9.18, I run into a class definition with parent Class and some optional argument, when I look it up, I know that python 3.6 add a new feature __init_subclass__() method for parent class, but the book is written based on Python3.3, so what method will take these arguments other than a metaclass

the class definition is here:

    class Spam(Base, debug=True, typecheck=False):
        ...

I know that metaclass can accept other optional arguments in its' __prepare__, __new__, __init__ method, but Base is a parent class, where do these argument go

回答1:

They go to the metaclass's __prepare__ method, just like always. Just because Base hasn't specified a metaclass doesn't mean it doesn't have one. The default metaclass is type.

The addition of __init_subclass__ to type in Python 3.6 just saves you the effort of defining a custom metaclass in order to implement an equivalent to __init_subclass__ yourself.



回答2:

The __init_subclass__ is an addition to Python 3.6 to reduce the need for custom metaclasses, as many of its uses are "overkill". The idea is that each subclass that is created for a (normal, non-meta) base-class that contains an __init_subclass__ method, it willbe called, with the new subclass as first parameter:

class Base:
   def __init_subclass__(subclass, debug=None, typecheck=None, **kwargs):
        # do stuff with the optional debug and typecheck arguments
        # Pass possible arguments not consumed here to superclasses, if any:
        super().__init_subclass__(**kwargs)

And there is no need for a metaclass at all - the __prepare__, __init__ and __new__ of the default metaclass - type - will ignore any named argument passed in this way. But the default __init_subclass__ in object will raise if unknown named arguments reach it - the pattern above will consume these arguments, removing them from kwargs. If you are dealing with unknown named arguments, just process kwargs like a normal dictionary - no need for explicit named parameters in the __init_subclass__.