首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >理解__init_subclass__

理解__init_subclass__
EN

Stack Overflow用户
提问于 2017-07-30 13:25:33
回答 5查看 56.6K关注 0票数 106

我最终升级了python版本,并发现了添加的新特性。除其他外,我在新的__init_subclass__方法上绞尽脑汁。从医生那里:

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

因此,我开始使用它,遵循文档中的示例:

代码语言:javascript
运行
复制
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)

产生这个输出:

代码语言:javascript
运行
复制
Called __init_subclass(<class '__main__.AustralianPhilosopher'>, 'Bruce')
'Set name to Hegel'
Called __init_subclass(<class '__main__.GermanPhilosopher'>, 'Nietzsche')
'Bruce'
'Nietzsche'

我知道这个方法是在子类定义之后调用的,但是我的问题是关于这个特性的用法。我也读过佩普487的文章,但对我没有多大帮助。这种方法有什么用呢?是为了:

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

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

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2017-07-30 13:36:09

__init_subclass____set_name__是正交的机制--它们不是相互联系的,只是在相同的PEP中描述。这两种特性都需要一个功能齐全的元类。PEP 487涉及两种最常见的元类用途:

  • 如何让父类知道它何时被子类(__init_subclass__)
  • 如何让描述符类知道它所使用的属性的名称(__set_name__)

正如佩普487所说:

虽然使用元类有许多可能的方法,但绝大多数用例只分为三类:类创建后运行的初始化代码、描述符的初始化以及保持类属性定义的顺序。 通过在类创建中使用简单的钩子,可以很容易地实现前两个类别:

  • 初始化给定类的所有子类的__init_subclass__钩子。
  • 在创建类时,将对类中定义的所有属性(描述符)调用__set_name__挂钩,并且

第三类是另一个PEP的主题,PEP 520

还请注意,虽然__init_subclass__是在该类的继承树中使用元类的替代,但描述符类中的__set_name__是对具有描述符实例作为属性的类使用元类的替换。

票数 54
EN

Stack Overflow用户

发布于 2017-07-30 13:56:26

佩普487开始使用两个常见的元类应用程序,使它们更容易访问,而不必理解元类的所有细节。__init_subclass____set_name__这两个新特性在其他方面是独立的,它们不相互依赖。

__init_subclass__只是一个钩子方法。你可以用它做任何你想要的事。它对于以某种方式注册子类和在这些子类上设置默认属性值都很有用。

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

代码语言:javascript
运行
复制
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

让我们为特定的存储库定义处理程序类,而不必使用元类或装饰器。

票数 88
EN

Stack Overflow用户

发布于 2017-07-31 11:47:52

我想添加一些有关元类和__init_subclass__的参考资料,这可能是有帮助的。

背景

__init_subclass__是作为创建元类的一种替代方法引入的。以下是核心开发人员之一布雷特·坎农( Brett )对佩普487谈话中的2分钟总结。

推荐参考资料

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45400284

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档