Python Mixins:调用super()时如何处理*args与**kwargs?
如何让Mixin支持任意组合与继承顺序?
下面的示例尝试使用Mixin模式,但运行时会触发类型错误:
class AMixin(): def __init__(self, **kwargs): print("AMixin") self.a = 'a' + str(kwargs.get('a', '')) super().__init__(**kwargs) class BMixin(): def __init__(self, **kwargs): print("BMixin") self.b = 'b' + str(kwargs.get('b', '')) super().__init__(**kwargs) class ABMixin(AMixin, BMixin): def __init__(self, **kwargs): print("ABMixin") super().__init__(**kwargs) class A(AMixin): def __init__(self, **kwargs): super().__init__(**kwargs) class B(BMixin): def __init__(self, **kwargs): super().__init__(**kwargs) class AB(ABMixin): def __init__(self, **kwargs): print("AB") super().__init__(**kwargs) AB(a='a', b='b')
错误信息
Cell In [4], line 9, in BMixin.__init__(self, *args, **kwargs) 8 def __init__(self, *args, **kwargs): ----> 9 super().__init__(*args, **kwargs) 10 print("BMixin") 11 self.b = 'b' + str(kwargs.get('b', '')) TypeError: object.__init__() takes exactly one argument (the instance to initialize)
错误原因
Python的多继承方法解析顺序(MRO)中,当Mixin通过super()调用父类构造方法时,继承链的最终节点是object类。而object.__init__仅接受self一个参数,传入额外的**kwargs就会触发类型错误。
解决方案
方案1:添加空基类EndMixin
创建一个空的EndMixin作为所有Mixin的基类,它的__init__方法接收**kwargs但不做任何逻辑处理,让继承链的最终节点指向它而非object:
class EndMixin: def __init__(self, **kwargs): pass # 仅接收参数,无实际逻辑 class AMixin(EndMixin): def __init__(self, **kwargs): print("AMixin") self.a = 'a' + str(kwargs.get('a', '')) super().__init__(**kwargs) # 传递参数到下一个节点 class BMixin(EndMixin): def __init__(self, **kwargs): print("BMixin") self.b = 'b' + str(kwargs.get('b', '')) super().__init__(**kwargs)
这样无论Mixin以何种顺序组合,super()调用最终都会落到EndMixin.__init__,不会触发参数错误。
方案2:动态判断父类__init__参数
如果不想额外添加基类,可以在每个Mixin的__init__中,先判断父类的构造方法是否接受关键字参数,再决定如何调用:
import inspect class AMixin(): def __init__(self, **kwargs): print("AMixin") self.a = 'a' + str(kwargs.get('a', '')) # 获取父类构造方法的签名 parent_init = super().__init__ sig = inspect.signature(parent_init) # 检查是否支持关键字参数 supports_kwargs = any(param.kind == param.VAR_KEYWORD for param in sig.parameters.values()) if supports_kwargs: super().__init__(**kwargs) else: super().__init__() class BMixin(): def __init__(self, **kwargs): print("BMixin") self.b = 'b' + str(kwargs.get('b', '')) parent_init = super().__init__ sig = inspect.signature(parent_init) supports_kwargs = any(param.kind == param.VAR_KEYWORD for param in sig.parameters.values()) if supports_kwargs: super().__init__(**kwargs) else: super().__init__()
这种方式无需额外基类,但代码相对繁琐,适合无法修改Mixin继承结构的场景。
内容的提问来源于stack exchange,提问作者nowox
相关产品推荐
相关产品推荐

