这似乎是一项如此简单的任务,但我现在在这上面花费了太多时间,却没有找到解决方案。这是设置:
class A(object):
def __init__(self, x=0):
print("A.__init__(x=%d)" % x)
class B(object):
def __init__(self, y=1):
print("B.__init__(y=%d)" % y)
class C(A, B):
def __init__(self, x=2, y=3, z=4):
super().__init__(x=x, y=y)
print("C.__init__(z=%d)" % z)
这就是想法,但当然这会导致
TypeError: __init__() got an unexpected keyword argument 'y'
所有其他尝试都以类似的方式失败,我在互联网上找不到没有具有正确解决方案的资源。唯一的解决方案包括用 *args, **kwargs
替换所有初始化参数。这不太符合我的需求。
根据要求,一个真实世界的例子:
(这使用了不同的方法,它具有有效的语法,但会产生不需要的结果。)
from PyQt5.QtCore import QObject
class Settings(object):
def __init__(self, file):
self.file = file
class SettingsObject(object):
def __init__(self, settings=None):
print("Super Init", settings is None)
self.settings = settings
class MyObject(QObject, SettingsObject):
def __init__(self, param):
print("Entering Init")
QObject.__init__(self)
SettingsObject.__init__(self, settings=Settings(__file__))
self.param = param
print("Leaving Init")
结果:
Entering Init
Super Init True
Super Init False
Leaving Init
我希望 Super Init True
行消失。
最佳答案
您似乎对一些事情感到困惑,所以:
为什么会出现
TypeError: __init__() got an unexpected keyword argument 'y'
?因为方法解析顺序(MRO)中
__init__
的下一个实现是A.__init__
,它只接受x
。 MRO是C
->A
->B
,所以你必须让A.__init__
接受y
(具体或使用**kwargs
)并将其传递(再次使用super
)到B.__init__
。super
不会调用 every 实现,当然也不能确保它们都只得到它们期望的参数,它只是调用 next 使用给定的所有参数实现。为什么
SettingsObject.__init__
被调用两次,一次有settings
,一次没有?看起来
QObject.__init__
包含对super().__init__
的调用,它会调用SettingsObject.__init__
MyObject
的 MRO。但是它不传递任何settings
参数,因此第一次调用它时您会看到settings is None
。第二次直接调用它并显式传递settings
,因此您会看到settings is not None
。如何编写混合类?
我认为这是您真正应该问的问题。
SettingsObject
应该是一个混入类,因此应正确设计以与它混入的层次结构中的其他类协作。在这种情况下:class SettingsObject: # (object) isn't needed in 3.x def __init__(self, *args, settings=None, **kwargs): super().__init__(*args, **kwargs) self.settings = settings
从您的示例来看,
QObject.__init__
没有任何必需的参数,但您仍然应该编写混合函数以在可选参数或在其他地方重用的情况下发挥良好的作用。然后MyObject
实现如下所示:class MyObject(SettingsObject, QObject): def __init__(self, param): super().__init__(settings=Settings(file)) self.param = param
注意:
- 混合类在子类化时最先出现,所以MRO是
MyObject
->SettingsObject
->QObject
;和 - 您调用
super().__init__
一次,而不是分别调用每个父类(super class)实现。
- 混合类在子类化时最先出现,所以MRO是
作为替代方案,您是否考虑过组合?也许 MyObject
应该采用设置:
class MyObject(QObject):
def __init__(self, param, settings=None):
super().__init__()
self.param = param
self.settings = settings
obj = MyObject('something', Settings(__file__))
现在你调用 self.settings.method(...)
而不是 self.method(...)
,但你没有那么复杂多重继承介绍。
关于python - 具有不同初始化参数的多重继承的真正解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44475984/