Python类分层继承查询
我正在努力建立一个班级结构。我在尝试访问父类的属性时遇到了问题(即,当我继承BaseX和BaseY时,BaseX的属性出现在子类中,而不是BaseY),我尝试继承父类,并在这里浏览了不同的帖子,最后找到了下面的结构,这与我对实际代码所做的类似;我对下面的结构进行了更多的实验,虽然只是为了理解概念。实际代码从一个父类开始,然后多个第1层子类继承它,然后还有其他第2层子类,它们的数量小于第1层子类的数量,然后我将所有第2层子类合并到一个类中。现在,经过大量的研发,我发现下面的代码正在做我想做的事情(可以访问SubABC类中的所有属性),但我不确定这是否正确,因为尽管实现了这一点,我不清楚super()在这里到底是如何工作的。在继续之前,我想清楚我正在做什么。例如,为什么单个super()在MidA和MidB中足够,但在MidC中需要三个super()。为什么SubABC只需要一个super()。在我将其复制到我的代码中之前,我希望在这里得到一些指导。我不是Python专家,所以如果我需要阅读一些东西,比如super()上的文档,请给我指出正确的方向。此外,PyCharm(2019.3.1-社区版)抱怨MidA super()。init(x_var,z_var)和MidB super()。init(x_var,z_var)语句表示“意外参数”;不确定这是否只是一个bug。谢谢Python类分层继承查询,python,python-3.x,Python,Python 3.x,我正在努力建立一个班级结构。我在尝试访问父类的属性时遇到了问题(即,当我继承BaseX和BaseY时,BaseX的属性出现在子类中,而不是BaseY),我尝试继承父类,并在这里浏览了不同的帖子,最后找到了下面的结构,这与我对实际代码所做的类似;我对下面的结构进行了更多的实验,虽然只是为了理解概念。实际代码从一个父类开始,然后多个第1层子类继承它,然后还有其他第2层子类,它们的数量小于第1层子类的数量,然后我将所有第2层子类合并到一个类中。现在,经过大量的研发,我发现下面的代码正在做我想做的事情(
class BaseX(object):
def __init__(self, x_var):
print('++++ Class BaseX')
self.x_var = x_var
print('---- Class BaseX')
class BaseY(object):
def __init__(self):
print('++++ Class BaseY')
self.y_var = 'Y_Var'
print('---- Class BaseY')
class BaseZ(object):
def __init__(self, z_var):
print('++++ Class BaseZ')
self.z_var = z_var
print('---- Class BaseZ')
class MidA(BaseX, BaseY, BaseZ):
def __init__(self, x_var, z_var):
print('++++ Class MidA')
super().__init__(x_var, z_var)
print('---- Class MidA')
def mid_a_func(self):
print(self.x_var)
print(self.y_var)
print(self.z_var)
class MidB(BaseX, BaseY, BaseZ):
def __init__(self, x_var, z_var):
print('++++ Class MidB')
super().__init__(x_var, z_var)
print('---- Class MidB')
def mid_b_func(self):
print(self.x_var)
print(self.y_var)
print(self.z_var)
class MidC(BaseX, BaseY, BaseZ):
def __init__(self, x_var, z_var):
print('++++ Class MidC')
super().__init__(x_var)
super(BaseX, self).__init__()
super(BaseY, self).__init__(z_var)
print('---- Class MidC')
def mid_b_func(self):
print(self.x_var)
print(self.y_var)
print(self.z_var)
class SubABC(MidA, MidB, MidC):
def __init__(self, x_var, z_var):
print('++++ Class SubABC')
super().__init__(x_var, z_var)
print('---- Class SubABC')
def sub_ab_func(self):
self.mid_a_func()
ab = SubABC('X_Var', 'Z_Var')
ab.sub_ab_func()
输出为:
++++ Class SubABC
++++ Class MidA
++++ Class MidB
++++ Class MidC
++++ Class BaseX
---- Class BaseX
++++ Class BaseY
---- Class BaseY
++++ Class BaseZ
---- Class BaseZ
---- Class MidC
---- Class MidB
---- Class MidA
---- Class SubABC
X_Var
Y_Var
Z_Var
出现这种意外行为的原因是Python中的
super
在没有参数的情况下调用时返回继承树中下一个类的实例
考虑以下示例(参数lvl
指的是缩进级别,因此我们可以更清楚地看到层次结构):
让我们构建一个“继承树”:
- Top
- Mid
- Base
绘制为单线,可以用以下方式表示:
Top -> Mid -> Base
因此,在Top
中,super()
返回下一项的实例,也就是Mid
。然后在Mid
中,它返回Base
的一个实例
毫不奇怪,我们得到了这样的输出:
+ Top
+ Mid
+ Base
- Base
- Mid
- Top
++++ Class SubABC
++++ Class MidA
++++ Class MidB
++++ Class MidC
++++ Class BaseX
---- Class BaseX
++++ Class BaseX
---- Class BaseX
++++ Class BaseY
---- Class BaseY
++++ Class BaseZ
---- Class BaseZ
---- Class MidC
---- Class MidB
---- Class MidA
---- Class SubABC
有趣的是,我们可以在不改变输出的情况下将代码更改为:
class Base:
def __init__(self, lvl):
print(lvl, "+ Base")
print(lvl, "- Base")
class Mid:
def __init__(self, lvl):
print(lvl, "+ Mid")
super().__init__(lvl + "\t")
print(lvl, "- Mid")
class Top(Mid, Base):
def __init__(self):
print(" + Top")
super().__init__("\t")
print(" - Top")
t = Top()
因为这棵树
- Top
- Mid
- Base
现在仍然是
Top -> Mid -> Base
现在让我们看一下您的示例中的“树”:
- SubABC
- MidA
- BaseX
- BaseY
- BaseZ
- MidB
- BaseX
- BaseY
- BaseZ
- MidC
- BaseX
- BaseY
- BaseZ
这变成了
SubABC -> MidA -> MidB -> MidC -> BaseX -> BaseY -> BaseZ
因此,SubABC
中的super()
转到MidA
,在MidA
中转到MidB
,等等
因此,当我们到达BaseX
时,我们将尽我们所能BaseX
没有对super()
的调用,因此永远不会从中执行BaseY
。因此,我们必须显式地调用BaseY
和BaseZ
如果我们将缩进级别应用于代码,我们将得到以下输出:
+ Top
+ Mid
+ Base
- Base
- Mid
- Top
++++ Class SubABC
++++ Class MidA
++++ Class MidB
++++ Class MidC
++++ Class BaseX
---- Class BaseX
++++ Class BaseX
---- Class BaseX
++++ Class BaseY
---- Class BaseY
++++ Class BaseZ
---- Class BaseZ
---- Class MidC
---- Class MidB
---- Class MidA
---- Class SubABC
您必须在MidC
中使用super(BaseX,self)。\uuuu init\uuuu()
,而不是super(BaseY,self)。\uuuu init\uuuuu()
是因为您需要调用下一个父级(BaseY
)的方法,而实现这一点的唯一方法是像运行BaseX
的方法一样运行super()
希望这有帮助。这能回答您的问题吗?