Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding __init_subclass__

I finally upgraded my python version and I was discovering the new features added. Among other things, I was scratching my head around the new __init_subclass__ method. From the docs:

This method is called whenever the containing class is subclassed. cls is then the new subclass. If defined as a normal instance method, this method is implicitly converted to a class method.

So I started to playing around with it a little bit, following the example in the docs:

class Philosopher:     def __init_subclass__(cls, default_name, **kwargs):         super().__init_subclass__(**kwargs)         print(f"Called __init_subclass({cls}, {default_name})")         cls.default_name = default_name  class AustralianPhilosopher(Philosopher, default_name="Bruce"):     pass  class GermanPhilosopher(Philosopher, default_name="Nietzsche"):     default_name = "Hegel"     print("Set name to Hegel")  Bruce = AustralianPhilosopher() Mistery = GermanPhilosopher() print(Bruce.default_name) print(Mistery.default_name) 

Produces this output:

Called __init_subclass(<class '__main__.AustralianPhilosopher'>, 'Bruce') 'Set name to Hegel' Called __init_subclass(<class '__main__.GermanPhilosopher'>, 'Nietzsche') 'Bruce' 'Nietzsche' 

I understand that this method is called after the subclass definition, but my questions are particularly about the usage of this feature. I read the PEP 487 article as well, but didn't help me much. Where would this method be helpful? Is it for:

  • the superclass to register the subclasses upon creation?
  • forcing the subclass to set a field at definition time?

Also, do I need to understand the __set_name__ to fully comprehend its usage?

like image 788
EsotericVoid Avatar asked Jul 30 '17 13:07

EsotericVoid


People also ask

What is __ Init_subclass __ in Python?

__init_subclass__(cls) method is called on a given class each time a subclass cls for that class is created. Syntax. Minimal Example. Class Hierarchy with __init_subclass__()

What does super () __ Init__ do?

Understanding Python super() with __init__() methods It is known as a constructor in Object-Oriented terminology. This method when called, allows the class to initialize the attributes of the class. The super() function allows us to avoid using the base class name explicitly.

What is a meta class in Python?

A metaclass in Python is a class of a class that defines how a class behaves. A class is itself an instance of a metaclass. A class in Python defines how the instance of the class will behave. In order to understand metaclasses well, one needs to have prior experience working with Python classes.

What is CLS Django?

cls accepts the class Person as a parameter rather than Person's object/instance. Now, we pass the method Person. printAge as an argument to the function classmethod . This converts the method to a class method so that it accepts the first parameter as a class (i.e. Person).


1 Answers

PEP 487 sets out to take two common metaclass usecases and make them more accessible without having to understand all the ins and outs of metaclasses. The two new features, __init_subclass__ and __set_name__ are otherwise independent, they don't rely on one another.

__init_subclass__ is just a hook method. You can use it for anything you want. It is useful for both registering subclasses in some way, and for setting default attribute values on those subclasses.

We recently used this to provide 'adapters' for different version control systems, for example:

class RepositoryType(Enum):     HG = auto()     GIT = auto()     SVN = auto()     PERFORCE = auto()  class Repository():     _registry = {t: {} for t in RepositoryType}      def __init_subclass__(cls, scm_type=None, name=None, **kwargs):         super().__init_subclass__(**kwargs)         if scm_type is not None:             cls._registry[scm_type][name] = cls  class MainHgRepository(Repository, scm_type=RepositoryType.HG, name='main'):     pass  class GenericGitRepository(Repository, scm_type=RepositoryType.GIT):     pass 

This trivially let us define handler classes for specific repositories without having to resort to using a metaclass or decorators.

like image 137
Martijn Pieters Avatar answered Oct 06 '22 00:10

Martijn Pieters