我写了钻石继承类。如果在同一级别有两个类,那么构造函数的参数列表长度不同,并且取决于基声明列表中的声明顺序,所有操作正常或立即抛出错误
class DFT(Common.BaseAS, Common.Signal):
def __init__(self, fs, N, history_len=1, strict=False):
super().__init__(fs, N, history_len, strict, np.complex)
class BaseAS(abc.ABC, AnalysisResultSaver):
No constructor here
class AnalysisResultSaver(Base):
def __init__(self, fs=8000, N=250, history_len=1, strict=False, dtype=None):
super().__init__(fs, N, dtype)
class Signal(Base):
def __init__(self, fs, N, dtype=None):
super().__init__(fs, N, dtype)
class Base:
def __init__(self, fs, N, dtype=None):
Stuff
构造函数的调用顺序如下:
DFT
;
AnalysisResultSaver
;
Signal
;
Base
在这种情况下,一切正常,但我的问题是
1) 如果没有直接指示哪些参数是正确的,那么参数是如何传递给Signal
构造函数的,它只是被修剪到前两个吗
但如果我改变DFT中基的顺序,我得到
super().__init__(fs, N, history_len, strict, np.complex)
TypeError: __init__() takes from 3 to 4 positional arguments but 6 were given
我知道它改变了mro,但在第一种情况下,它工作得很好
如果我想通过Common.BaseAS.__init__()
直接调用构造函数
而且Common.Signal.__init__()
than信号构造函数被调用了两次,所以对BaseAS的调用会调用信号构造函数,即使它不是它的父构造函数
Common.BaseAS.__init__(self, fs, N, history_len, strict, np.complex)
Common.Signal.__init__(self, fs, N)
那么BaseAS
如何调用Signal
构造函数呢
在您的示例中,
AnalysisResultSaver.__init__
中的超级调用是调用Signal.__init__
的。这可能是违反直觉的,因为Signal
不是AnalysisResultSaver
的超类,并且是Python中多重继承和super
函数工作的有趣方式的一个示例特别是,当您在
AnalysisResultSaver
中写入super()
时,这实际上是super(AnalysisResultSaver, self)
的简写。那么这到底是做什么的呢?它查看传入的实际实例(self
)的方法解析顺序,并尝试在传入的类(AnalysisResultSaver
)之后找到第一个匹配的方法如果按预期在
AnalysisResultSaver
中打印self.__class__
,您将看到对象本身是DFT
的实例。如果查看该类上的方法解析顺序self.__class__.__mro__
或仅仅DFT.__mro__
,您将看到一个类列表:DFT
,BaseAS
,AnalysisResultSaver
,Signal
,Base
,object
注意
AnalysisResultSaver
之后的第一个是Signal
,这就是它决定Signal.__init__
是它接下来应该调用的特定构造函数的方式如果您感兴趣,我建议您详细阅读Python的多重继承和
super
函数;网上有许多资源更全面地介绍了这个主题@KSab的答案是正确的,但我将添加这一点,因为它有助于说明正在发生的事情(并且是在该答案中提出的)。我对您的代码进行了一些修改,以准确地显示正在发生的事情以及这些对象的构造顺序。代码如下:
它将产生以下输出:
此外,这是每个类别的MRO:
相关问题 更多 >
编程相关推荐