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

为何相似__new__实现下__init__调用次数存在差异?

为什么传入自身作为基类时会多一次__init__调用?

问题根源

Python调用类创建实例的逻辑是固定的:

  1. 先调用类.__new__(类, *创建参数)生成实例
  2. 如果返回的实例属于该类(或其子类),Python会自动调用这个实例的__init__(*创建参数)
  3. 最后返回实例

结合你的代码看两种场景:

场景1:SomeClass(OtherClass)

  • SomeClass.__new__创建了继承自OtherClass的SomeClassCustom,实例化后返回这个对象
  • 因为SomeClassCustom不是SomeClass的子类,isinstance(返回实例, SomeClass)为False,所以Python不会额外调用它的__init__,只有实例化SomeClassCustom()时触发的一次初始化

场景2:SomeClass(SomeClass)

  • SomeClass.__new__创建了继承自SomeClass的SomeClassCustom,实例化过程:
    1. 调用继承来的SomeClassCustom.__new__,因real_base=None返回实例,此时Python触发第一次__init__(无参数)
    2. SomeClass.__new__返回这个实例,而SomeClassCustom是SomeClass的子类,isinstance(返回实例, SomeClass)为True,所以Python会把原调用的参数(SomeClass,)传给实例的__init__,触发第二次初始化

解决办法

办法1:切断继承关联(如果允许)

当real_base是SomeClass自身时,不让SomeClassCustom继承它,或者调整继承链,避免返回的实例属于原工厂类的子类:

# 创建新类时添加判断
if real_base is SomeClass:
    new_field_class = type(cls.__name__ + 'Custom', (object, ), {})
else:
    new_field_class = type(cls.__name__ + 'Custom', (real_base, ), {})

办法2:统一实例化参数

在工厂里创建实例时,直接把原调用的参数传递过去,这样即使后续触发第二次__init__,参数也能匹配:

# 修改res = new_field_class()为
res = new_field_class(*args, **kwargs)

办法3:拆分工厂类和业务类

最清晰的方式是把工厂逻辑和业务类分开,避免同一个类既做工厂又做实例类:

class SomeClass:
    def __init__(self, *args, **kwargs):
        print(f"{self.__class__.__name__}.__init__ got {args=}, {kwargs=}")

class SomeClassFactory:
    @classmethod
    def create(cls, real_base=None, *args, **kwargs):
        print(f"{cls.__name__}.create got {real_base=}, {args=}, {kwargs=}")
        if not real_base:
            return SomeClass(*args, **kwargs)
        new_class = type('SomeClassCustom', (real_base, ), {})
        return new_class(*args, **kwargs)

# 调用示例
SomeClassFactory.create(OtherClass)
SomeClassFactory.create(SomeClass)

这样工厂返回的实例和工厂类本身没有继承关系,不会触发额外的__init__,逻辑也更易懂。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:50:09