为何相似__new__实现下__init__调用次数存在差异?
为什么传入自身作为基类时会多一次__init__调用?
问题根源
Python调用类创建实例的逻辑是固定的:
- 先调用
类.__new__(类, *创建参数)生成实例 - 如果返回的实例属于该类(或其子类),Python会自动调用这个实例的
__init__(*创建参数) - 最后返回实例
结合你的代码看两种场景:
场景1:SomeClass(OtherClass)
SomeClass.__new__创建了继承自OtherClass的SomeClassCustom,实例化后返回这个对象- 因为
SomeClassCustom不是SomeClass的子类,isinstance(返回实例, SomeClass)为False,所以Python不会额外调用它的__init__,只有实例化SomeClassCustom()时触发的一次初始化
场景2:SomeClass(SomeClass)
SomeClass.__new__创建了继承自SomeClass的SomeClassCustom,实例化过程:- 调用继承来的
SomeClassCustom.__new__,因real_base=None返回实例,此时Python触发第一次__init__(无参数) 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
相关产品推荐
相关产品推荐

