You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python继承类实例时__init__被调用两次的原因探究

Python类继承实例的运行机制问题解析

先看两段测试代码

正常继承类的代码

class Foo:
    def __init__(self):
        print("Foo.__init__ called")

class Bar(Foo):
    pass

bar = Bar()  # 输出:Foo.__init__ called

这段代码符合预期:实例化Bar时,会调用父类Foo的构造函数。

错误继承实例的代码

class Foo:
    def __init__(self, *args):
        print(f"Foo.__init__ called with args: {args}")

foo = Foo()  # 第一次调用,输出:Foo.__init__ called with args: ()
class Bar(foo):  # 继承的是foo实例而非Foo类
    pass
# 第二次调用,输出:Foo.__init__ called with args: ('Bar', (<__main__.Foo object at 0x...>,), {'__module__': '__main__', '__qualname__': 'Bar'})

这段代码中Foo.__init__被调用了两次,第二次传入的是创建类时的标准参数。


解答三个疑问

1. 该过程实际是如何发生的?

当执行class Bar(foo):时,Python内部的执行流程是:

  • 先解析类体代码,生成包含类属性、方法的命名空间字典。
  • 调用默认元类type创建Bar类,本质执行的是type('Bar', (foo,), 命名空间字典)。
  • 由于基类元组里的foo是实例而非类,type在处理这种非常规输入时,会触发foo所属类(Foo)的__init__方法,并且把创建类的三个核心参数(类名、基类元组、命名空间字典)传入,这就导致了Foo.__init__的第二次调用。

2. 为什么继承Foo实例会导致Foo.__init__传入类创建参数被调用?

正常继承时,基类元组里的元素都是类,type会直接处理这些类来构建子类的继承关系。但当传入实例时,type无法将实例当作类来处理继承逻辑,它会触发一个 fallback 逻辑:调用该实例所属类的__init__方法,并把创建新类的参数传递进去。这是Python解释器处理非类基元的一种尝试,而非直接抛出错误。

3. 为什么没有调用type("Bar", , )来生成类?

实际上底层还是调用了type,只是调用过程中因为基类是实例,触发了额外的Foo.__init__调用。最终Bar类会被正常生成,你可以通过print(Bar.__bases__)验证,它的基类元组确实包含foo实例。所谓“没有调用type”是一种误解,type的调用是类创建的核心,只是附加了额外的构造函数调用行为。


内容的提问来源于stack exchange,提问作者David McLean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 06:10:28