Python类模型中__new__、__init__调用逻辑及元类报错咨询
__new__方法与__init__执行逻辑的疑问 问题背景
我最近在深入研究Python类模型的细节,通过装饰器、元类、父类做了不少实验,目前重点在搞懂__new__方法的作用,还写了测试模块来验证。
运行测试后发现两个现象:
- 我的
Super类没有自动执行__init__方法,但在Simple类的__new__里手动调用instance.__init__(instance, *list, **map)之后,__init__才执行了; - 创建
Triple实例的时候报错:TypeError: __new__() missing 3 required positional arguments: 'name', 'supers', and 'attributes'。
现在我有个核心疑问:是不是应该在自定义的__new__方法末尾手动调用instance.__init__? 我原本以为在自定义的__call__方法里调用object.__call__会自动处理__init__的执行流程。
解答
先直接给结论:通常情况下,你完全不需要手动在__new__里调用__init__——Python的默认实例创建流程会帮你处理这件事,但前提是你没有打破这个默认逻辑链。
为什么你的Super类没自动执行__init__?
Python默认的实例创建逻辑是:当你调用类(比如Super())时,实际是触发了类的__call__方法(对于普通类来说,这个方法来自type元类)。__call__会先调用类的__new__创建实例,只有当__new__返回的是当前类(或其子类)的实例时,Python才会自动调用这个实例的__init__,并把创建时传入的参数传递进去。
你在Simple类的__new__里手动调用instance.__init__能生效,是因为你绕开了默认触发逻辑,但这不是规范做法——除非你有特别的需求(比如要精准控制__init__的执行时机、修改传入参数,或者__new__返回的不是当前类的对象)。
关于Triple类的报错
这个报错说明你在调用Triple()创建实例时,没有给它的__new__方法传要求的三个参数name、supers、attributes。这里大概率是因为Triple是一个自定义元类——元类的__new__方法在创建类时,会自动接收这三个参数(类名、父类元组、类属性字典),但如果你把它当普通类直接实例化,自然会因为参数不匹配报错。正确的用法应该是用它创建类,比如MyClass = Triple('MyClass', (object,), {}),而不是直接obj = Triple()。
回到你的核心疑问
你提到“在自定义__call__里调用object.__call__”——这里要注意:触发__new__和__init__的核心逻辑其实来自type.__call__(因为普通类都是type的实例)。如果你自定义了元类的__call__方法,必须确保在里面正确调用super().__call__(*args, **kwargs),这样才能让默认的__new__+__init__流程正常跑起来。
只有在以下几种特殊场景下,才需要考虑手动调用__init__:
__new__返回的不是当前类的实例(比如返回了另一个类的对象或者None)- 你需要在
__init__执行前后做特殊操作,且完全不想依赖默认触发逻辑 - 你在元类层面完全重写了实例创建的全流程
小建议
如果你的测试代码里涉及自定义元类,可以检查这几点:
- 元类的
__call__方法是否正确调用了父类的__call__方法 - 普通类的
__new__是否正确返回了当前类的实例,没有破坏默认流程 - 确认
Triple的定位:如果是元类,就用来创建类,不要直接实例化它
内容的提问来源于stack exchange,提问作者Anthony

