简体   繁体   English

Python 类分层继承查询

[英]Python Class Layered Inheritence Query

I am trying to develop a class structure.我正在尝试开发一个类结构。 I ran into problems trying to access attributes of parent classes (ie when I inherited BaseX and BaseY, the attributes of BaseX appeared in child class but not of BaseY) trying to inherit parent classes and went through different posts here and finally came to below structure which is similar to what I am doing with my actual code;我在尝试访问父类的属性时遇到了问题(即当我继承 BaseX 和 BaseY 时,BaseX 的属性出现在子类中而不是 BaseY 中)试图继承父类并在这里浏览不同的帖子,最后来到下面的结构这与我对实际代码所做的类似; I have been more experimental with the structure below though just to understand concepts.我对下面的结构进行了更多的实验,尽管只是为了理解概念。 The actual code starts with a single parent class, then multiple layer 1 child classes inherit it, then there are further layer 2 child classes which are less than the number of layer 1 child classes and then I merge all layer 2 child classes in to one class.实际代码以单个父类开始,然后多个第 1 层子类继承它,然后还有小于第 1 层子类数量的第 2 层子类,然后我将所有第 2 层子类合并为一个班级。 Now after a lot of R&D, I found a code below which is doing what I want (can access all attributes in class SubABC) but I am not sure if this is correct as despite achieving this, I am not clear on how exactly this super() is working here.现在经过大量的研发,我发现下面的代码正在做我想做的事情(可以访问类 SubABC 中的所有属性)但我不确定这是否正确,因为尽管实现了这一点,我不清楚这个超级() 在这里工作。 And I would like to be clear with what I am doing before proceeding.在继续之前,我想清楚我在做什么。 For example, why single super() is sufficient in MidA and MidB but requires three super() in MidC.例如,为什么在 MidA 和 MidB 中单个 super() 就足够了,而在 MidC 中需要三个 super()。 And why SubABC requires only one super().以及为什么 SubABC 只需要一个 super()。 I would appreciate some guidance here before I replicate this in to my code.在将其复制到我的代码中之前,我会很感激这里的一些指导。 I am no Python expert so please do point me in right direction if I need to read something - ie documentation on super().我不是 Python 专家,所以如果我需要阅读一些东西,请给我指出正确的方向 - 即关于 super() 的文档。 Also, PyCharm (2019.3.1 - Community Edition) complains about MidA super().此外,PyCharm(2019.3.1 - 社区版)抱怨 MidA super()。 init (x_var, z_var) and MidB super(). init (x_var, z_var) 和 MidB super()。 init (x_var, z_var) statements saying 'unexpected arguments'; init (x_var, z_var) 语句说“意外参数”; not sure if it is just a bug.不确定这是否只是一个错误。 Thanks.谢谢。

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

The output is:输出是:

++++ 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

The reason you're getting this unexpected behaviour is that super in Python when called with no arguments returns an instance of the next class in the inheritance tree.出现这种意外行为的原因是 Python 中的super在不带参数的情况下调用时会返回继承树中下一个类的实例。

Consider the following example (the argument lvl refers to an indent-level so we can more clearly see the hierarchy):考虑以下示例(参数lvl指的是缩进级别,因此我们可以更清楚地看到层次结构):

class Base:
    def __init__(self, lvl):
        print(lvl, "+ Base")
        print(lvl, "- Base")

class Mid(Base):
    def __init__(self, lvl):
        print(lvl, "+ Mid")
        super().__init__(lvl + "\t")
        print(lvl, "- Mid")

class Top(Mid):
    def __init__(self):
        print(" + Top")
        super().__init__("\t")
        print(" - Top")

t = Top()

Let's build an 'inheritance tree':让我们构建一个“继承树”:

- Top
    - Mid
        - Base

Drawn as a single line, it can be represented with this:绘制为一条线,它可以用这个表示:

Top -> Mid -> Base

So, in Top , super() returns an instance of the next item, so of Mid .因此,在Topsuper()返回下一项的实例,即Mid Then in Mid , it returns an instance of Base .然后在Mid ,它返回Base一个实例。

Unsurprisingly, we get this output:不出所料,我们得到了这个输出:

 + Top
     + Mid
         + Base
         - Base
     - Mid
 - Top

Interestingly, we could change the code to this without any change in the output:有趣的是,我们可以在不改变输出的情况下将代码更改为:

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

because this tree is因为这棵树是

- Top
    - Mid
    - Base

which still becomes这仍然成为

Top -> Mid -> Base

Now let's at the look at the 'tree' for your example:现在让我们看看示例中的“树”:


- SubABC
    - MidA
        - BaseX
        - BaseY
        - BaseZ
    - MidB
        - BaseX
        - BaseY
        - BaseZ
    - MidC
        - BaseX
        - BaseY
        - BaseZ

This turns into这变成

SubABC -> MidA -> MidB -> MidC -> BaseX -> BaseY -> BaseZ

So, super() in SubABC goes to MidA , and in MidA to MidB , etc.因此, SubABC super()转到MidA ,在MidA转到MidB ,等等。

Thus, when we get to BaseX , we reach as far as we can go.因此,当我们到达BaseX ,我们会尽可能地到达。 BaseX does not have a call to super() , so BaseY is never executed from it. BaseX没有对super()的调用,因此BaseY永远不会从中执行。 Thus, we have to call BaseY and BaseZ explicitly.因此,我们必须显式调用BaseYBaseZ

If we apply the indent-level thing to your code, we get this output:如果我们将缩进级别应用于您的代码,我们会得到以下输出:


    ++++ 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

And the reason you have to use super(BaseX, self).__init__() in MidC , not super(BaseY, self).__init__() is because you need to call the method of the next parent ( BaseY ), and the only way to get to this is to run super() as though you were in a method of BaseX .而你必须在MidC使用super(BaseX, self).__init__()而不是super(BaseY, self).__init__()的原因是因为你需要调用下一个父级( BaseY )的方法,并且唯一达到此目的的方法是运行super()就像您在BaseX的方法中一样。

Hope this helps.希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM