y-s*_*een 5 python initialization multiple-inheritance python-3.x
这似乎是一个如此简单的任务,但我现在在这上面花了太多时间,没有解决方案。这是设置:
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)
Run Code Online (Sandbox Code Playgroud)
这就是想法,但这当然会导致
TypeError: __init__() got an unexpected keyword argument 'y'
Run Code Online (Sandbox Code Playgroud)
其他所有尝试都失败了类似的方式,我可以找到没有用正确的解决方案在互联网上的资源。唯一的解决方案包括将所有 init 参数替换为*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")
Run Code Online (Sandbox Code Playgroud)
结果:
Entering Init
Super Init True
Super Init False
Leaving Init
Run Code Online (Sandbox Code Playgroud)
我希望这条线Super Init True
消失。
您似乎对一些事情感到困惑,因此:
你为什么得到TypeError: __init__() got an unexpected keyword argument 'y'
?
因为__init__
在方法解析顺序 (MRO) 中的下一个实现是A.__init__
,它只接受x
. MRO 是C
-> A
-> B
,因此您必须A.__init__
接受y
(特别是或使用**kwargs
)并将其传递(super
再次使用)到B.__init__
.
super
不会调用每个实现,当然也不能确保它们都只得到他们期望的参数,它只是使用给定的所有参数调用下一个实现。
为什么会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
Run Code Online (Sandbox Code Playgroud)
从您的示例中看起来好像QObject.__init__
没有任何必需的参数,但是您仍然应该编写混合以在可选参数或在其他地方重用的情况下发挥良好的作用。然后MyObject
实现看起来像:
class MyObject(SettingsObject, QObject):
def __init__(self, param):
super().__init__(settings=Settings(file))
self.param = param
Run Code Online (Sandbox Code Playgroud)
注意:
MyObject
-> SettingsObject
-> QObject
;和super().__init__
一次,而不是分别调用每个超类实现。作为替代方案,您是否考虑过组合?也许MyObject
应该采取设置:
class MyObject(QObject):
def __init__(self, param, settings=None):
super().__init__()
self.param = param
self.settings = settings
obj = MyObject('something', Settings(__file__))
Run Code Online (Sandbox Code Playgroud)
现在您调用self.settings.method(...)
而不是self.method(...)
,但您没有多重继承引入的复杂性。