Python类分层继承查询

Python类分层继承查询,python,python-3.x,Python,Python 3.x,我正在努力建立一个班级结构。我在尝试访问父类的属性时遇到了问题(即,当我继承BaseX和BaseY时,BaseX的属性出现在子类中,而不是BaseY),我尝试继承父类,并在这里浏览了不同的帖子,最后找到了下面的结构,这与我对实际代码所做的类似;我对下面的结构进行了更多的实验,虽然只是为了理解概念。实际代码从一个父类开始,然后多个第1层子类继承它,然后还有其他第2层子类,它们的数量小于第1层子类的数量,然后我将所有第2层子类合并到一个类中。现在,经过大量的研发,我发现下面的代码正在做我想做的事情(

我正在努力建立一个班级结构。我在尝试访问父类的属性时遇到了问题(即,当我继承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。谢谢

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()


希望这有帮助。

这能回答您的问题吗?