为何type.__new__会调用__init_subclass__?Django类创建时序疑问
类创建流程中
__init_subclass__与元类的时序疑问 实际遇到的问题
- 尝试将
__init_subclass__应用到Django模型类时,无法达到预期效果 - 观察到父类的
__init_subclass__执行时,元类尚未完成子类的全部创建工作 - 已知该问题可以通过自定义元类规避,但始终不理解这种时序设计的原因
- 此前的固有认知是:所有类似
__new__的类构造操作,应当在所有类似__init__的类初始化操作之前全部完成,但实际观察到的执行时序和这个认知存在明显偏差
复现实验
测试代码
class MetaMeta(type): print('parsing MetaMeta') def __call__(cls, *args, **kwargs): print('entering MetaMeta.__call__') instance = super().__call__(*args, **kwargs) print('leaving MetaMeta.__call__') return instance class Meta(type, metaclass=MetaMeta): print('parsing Meta') def __init__(self, *args, **kwargs): print(' entering Meta.__init__') super().__init__(*args, **kwargs) print(' leaving Meta.__init__') def __new__(cls, *args, **kwargs): print(f' entering Meta.__new__') instance = super().__new__(cls, *args, **kwargs) print(' leaving Meta.__new__') return instance class Parent(object, metaclass=Meta): print('parsing Parent') def __init_subclass__(cls, *args, **kwargs): print(' entering Parent.__init_subclass__') super().__init_subclass__(*args, **kwargs) print(' leaving Parent.__init_subclass__') class Child(Parent): print('parsing Child')
运行输出结果
parsing MetaMeta parsing Meta parsing Parent entering MetaMeta.__call__ entering Meta.__new__ leaving Meta.__new__ entering Meta.__init__ leaving Meta.__init__ leaving MetaMeta.__call__ parsing Child entering MetaMeta.__call__ entering Meta.__new__ entering Parent.__init_subclass__ leaving Parent.__init_subclass__ leaving Meta.__new__ entering Meta.__init__ leaving Meta.__init__ leaving MetaMeta.__call__
时序观察与核心疑问
从输出可以看到明显的时序偏差:Parent.__init_subclass__的执行是嵌套在Meta.__new__的流程内部完成的,也就是说这个方法触发时,Meta.__new__还未走完整个执行流程,后续的Meta.__init__也尚未开始运行。
围绕这个偏差,核心的疑问包括:
- 为什么Python(至少在Python 3.9版本的实现中)选择让
Meta.__new__触发父类的__init_subclass__,而不是由外层的MetaMeta.__call__在__new__完全执行结束后再调用该方法?这种设计的原因是什么? - 有没有办法在不编写自定义元类的前提下,在
Parent类中实现一段逻辑,使其执行时机完全卡在Meta.__new__全部执行完成后、Meta.__init__开始执行前? - 自己此前对Python类创建流程的理解是否存在根本性偏差?
已参考的关联主题
在梳理问题的过程中,已查阅以下相关资料,但均未找到针对当前时序设计原因的明确解答:
- Python3元类的调用顺序
- 元类的
__new__与__init__方法参数 - Python官方文档中关于类创建自定义流程的说明
- 公开技术渠道关于该时序问题的历史工单与开发者邮件组讨论
内容的提问来源于stack exchange,提问作者Nonanon
相关产品推荐
相关产品推荐

