理解 __init_subclass__

2023-12-09

我终于升级了我的 python 版本,并且发现了添加的新功能。除此之外,我对新的东西感到摸不着头脑。__init_subclass__方法。来自文档:

每当包含类被子类化时,就会调用此方法。 CLS 然后是新的子类。如果定义为普通实例方法,则此 方法隐式转换为类方法。

所以我开始按照文档中的示例尝试一下:

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)

产生以下输出:

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

我明白这个方法被称为after子类定义,但我的问题特别是关于此功能的使用。我读了PEP 487文章也一样,但对我没有太大帮助。这个方法有什么用呢?是否用于:

  • 超类在创建时注册子类?
  • 强制子类在定义时设置字段?

另外,我需要了解__set_name__才能完全理解它的用法?


PEP 487着手采用两个常见的元类用例,并使它们更易于访问,而无需了解元类的所有来龙去脉。这两个新功能,__init_subclass__ and __set_name__否则独立的,他们不互相依赖。

__init_subclass__只是一个钩子方法。您可以将它用于任何您想要的用途。它对于以某种方式注册子类很有用,and用于设置这些子类的默认属性值。

我们最近用它来为不同的版本控制系统提供“适配器”,例如:

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

这让我们可以轻松地为特定存储库定义处理程序类,而不必求助于使用元类或装饰器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

理解 __init_subclass__ 的相关文章

随机推荐