super()如何处理多重继承?例如,给定:

class First(object):
    def __init__(self):
        print "first"

class Second(object):
    def __init__(self):
        print "second"

class Third(First, Second):
    def __init__(self):
        super(Third, self).__init__()
        print "that's it"

Third的哪个父方法执行super()。__init__ refer to?我可以选择哪些运行吗?

我知道这与方法解析顺序(MRO)有关。


当前回答

在学习python的过程中,我学到了一个叫做super()的东西,如果没有弄错的话,这是一个内置函数。调用super()函数可以帮助继承通过父节点和“兄弟节点”传递,并帮助你看得更清楚。我仍然是初学者,但我喜欢分享我在python2.7中使用这个super()的经验。

如果您已经阅读了本页中的注释,您将听说方法解析顺序(MRO),该方法是您编写的函数,MRO将使用深度优先的左至右方案来搜索和运行。你可以做更多的研究。

通过添加super()函数

super(First, self).__init__() #example for class First.

你可以用super()连接多个实例和“家族”,方法是添加其中的每个实例和每个人。它会执行这些方法,检查它们,确保你没有错过!然而,在之前或之后添加它们确实会有区别,你会知道你是否已经通过硬路练习学习了python。让乐趣开始吧!!

以下面的例子为例,你可以复制粘贴并试着运行它:

class First(object):
    def __init__(self):

        print("first")

class Second(First):
    def __init__(self):
        print("second (before)")
        super(Second, self).__init__()
        print("second (after)")

class Third(First):
    def __init__(self):
        print("third (before)")
        super(Third, self).__init__()
        print("third (after)")


class Fourth(First):
    def __init__(self):
        print("fourth (before)")
        super(Fourth, self).__init__()
        print("fourth (after)")


class Fifth(Second, Third, Fourth):
    def __init__(self):
        print("fifth (before)")
        super(Fifth, self).__init__()
        print("fifth (after)")

Fifth()

它是如何运行的?fifth()的实例如下所示。每一步从一个类到另一个类,其中添加了超函数。

1.) print("fifth (before)")
2.) super()>[Second, Third, Fourth] (Left to right)
3.) print("second (before)")
4.) super()> First (First is the Parent which inherit from object)

父母已经找到了,会继续到第三和第四!!

5.) print("third (before)")
6.) super()> First (Parent class)
7.) print ("Fourth (before)")
8.) super()> First (Parent class)

现在所有带有super()的类都已经被访问了!父类已经找到并执行,现在它继续在继承中解箱函数以完成代码。

9.) print("first") (Parent)
10.) print ("Fourth (after)") (Class Fourth un-box)
11.) print("third (after)") (Class Third un-box)
12.) print("second (after)") (Class Second un-box)
13.) print("fifth (after)") (Class Fifth un-box)
14.) Fifth() executed

以上方案的成果:

fifth (before)
second (before
third (before)
fourth (before)
first
fourth (after)
third (after)
second (after)
fifth (after)

对我来说,添加super()可以让我更清楚地看到python如何执行我的代码,并确保继承可以访问我想要的方法。

其他回答

整体

假设所有东西都来自object(如果不是你自己的),Python会根据你的类继承树计算一个方法解析顺序(MRO)。MRO满足3个性质:

一个阶层的孩子比他们的父母更重要 左父母先于右父母 一个类在MRO中只出现一次

如果不存在这样的顺序,Python将出错。它的内部工作原理是类祖先的C3线性化。点击这里阅读:https://www.python.org/download/releases/2.3/mro/

当一个方法被调用时,该方法在MRO中第一次出现就是被调用的方法。任何没有实现该方法的类都将被跳过。在该方法中对super的任何调用都将调用MRO中该方法的下一次出现。因此,在继承中放置类的顺序以及在方法中放置super调用的位置都很重要。

注意,你可以通过使用__mro__方法在python中看到MRO。

例子

下面所有的例子都有菱形类继承,如下所示:

    Parent
    /   \
   /     \
Left    Right
   \     /
    \   /
    Child

MRO是:

孩子 左 正确的 父

您可以通过调用Child来测试这一点。__mro__,返回:

(__main__.Child, __main__.Left, __main__.Right, __main__.Parent, object)

每一种方法都以超第一

class Parent(object):
    def __init__(self):
        super(Parent, self).__init__()
        print("parent")

class Left(Parent):
    def __init__(self):
        super(Left, self).__init__()
        print("left")

class Right(Parent):
    def __init__(self):
        super(Right, self).__init__()
        print("right")

class Child(Left, Right):
    def __init__(self):
        super(Child, self).__init__()
        print("child")

孩子()输出:

parent
right
left
child
    

在每个方法中都有超级最后

class Parent(object):
    def __init__(self):
        print("parent")
        super(Parent, self).__init__()

class Left(Parent):
    def __init__(self):
        print("left")
        super(Left, self).__init__()

class Right(Parent):
    def __init__(self):
        print("right")
        super(Right, self).__init__()

class Child(Left, Right):
    def __init__(self):
        print("child")
        super(Child, self).__init__()

孩子()输出:

child
left
right
parent

当不是所有类都调用super时

如果不是继承链中的所有类都调用super,那么继承顺序最重要。例如,如果Left不调用super,那么Right和Parent上的方法永远不会被调用:

class Parent(object):
    def __init__(self):
        print("parent")
        super(Parent, self).__init__()

class Left(Parent):
    def __init__(self):
        print("left")

class Right(Parent):
    def __init__(self):
        print("right")
        super(Right, self).__init__()

class Child(Left, Right):
    def __init__(self):
        print("child")
        super(Child, self).__init__()

孩子()输出:

child
left

或者,如果Right没有调用super, Parent仍然被跳过:

class Parent(object):
    def __init__(self):
        print("parent")
        super(Parent, self).__init__()

class Left(Parent):
    def __init__(self):
        print("left")
        super(Left, self).__init__()

class Right(Parent):
    def __init__(self):
        print("right")

class Child(Left, Right):
    def __init__(self):
        print("child")
        super(Child, self).__init__()

在这里,Child()输出:

child
left
right

调用特定父节点上的方法

如果你想访问一个特定父类的方法,你应该直接引用这个类,而不是使用super。Super是关于遵循继承链,而不是到达特定类的方法。

下面是如何引用一个特定的父方法:

class Parent(object):
    def __init__(self):
        super(Parent, self).__init__()
        print("parent")

class Left(Parent):
    def __init__(self):
        super(Left, self).__init__()
        print("left")

class Right(Parent):
    def __init__(self):
        super(Right, self).__init__()
        print("right")

class Child(Left, Right):
    def __init__(self):
        Parent.__init__(self)
        print("child")

在这种情况下,Child()输出:

parent
child

这就是所谓的钻石问题,该页面有一个关于Python的条目,但简而言之,Python将从左到右调用超类的方法。

把这个答案贴出来供我将来参考。

Python多重继承应该使用菱形模型,并且函数签名不应该在模型中更改。

    A
   / \
  B   C
   \ /
    D

示例代码片段为;-

class A:
    def __init__(self, name=None):
        #  this is the head of the diamond, no need to call super() here
        self.name = name

class B(A):
    def __init__(self, param1='hello', **kwargs):
        super().__init__(**kwargs)
        self.param1 = param1

class C(A):
    def __init__(self, param2='bye', **kwargs):
        super().__init__(**kwargs)
        self.param2 = param2

class D(B, C):
    def __init__(self, works='fine', **kwargs):
        super().__init__(**kwargs)
        print(f"{works=}, {self.param1=}, {self.param2=}, {self.name=}")

d = D(name='Testing')

这里类A是对象

在这种情况下,你试图继承的每个类都有自己的init位置参数,只需调用每个类自己的init方法,如果试图继承多个对象,则不要使用super。

class A():
    def __init__(self, x):
        self.x = x

class B():
    def __init__(self, y, z):
        self.y = y
        self.z = z

class C(A, B):
    def __init__(self, x, y, z):
        A.__init__(self, x)
        B.__init__(self, y, z)

>>> c = C(1,2,3)
>>>c.x, c.y, c.z 
(1, 2, 3)

在学习python的过程中,我学到了一个叫做super()的东西,如果没有弄错的话,这是一个内置函数。调用super()函数可以帮助继承通过父节点和“兄弟节点”传递,并帮助你看得更清楚。我仍然是初学者,但我喜欢分享我在python2.7中使用这个super()的经验。

如果您已经阅读了本页中的注释,您将听说方法解析顺序(MRO),该方法是您编写的函数,MRO将使用深度优先的左至右方案来搜索和运行。你可以做更多的研究。

通过添加super()函数

super(First, self).__init__() #example for class First.

你可以用super()连接多个实例和“家族”,方法是添加其中的每个实例和每个人。它会执行这些方法,检查它们,确保你没有错过!然而,在之前或之后添加它们确实会有区别,你会知道你是否已经通过硬路练习学习了python。让乐趣开始吧!!

以下面的例子为例,你可以复制粘贴并试着运行它:

class First(object):
    def __init__(self):

        print("first")

class Second(First):
    def __init__(self):
        print("second (before)")
        super(Second, self).__init__()
        print("second (after)")

class Third(First):
    def __init__(self):
        print("third (before)")
        super(Third, self).__init__()
        print("third (after)")


class Fourth(First):
    def __init__(self):
        print("fourth (before)")
        super(Fourth, self).__init__()
        print("fourth (after)")


class Fifth(Second, Third, Fourth):
    def __init__(self):
        print("fifth (before)")
        super(Fifth, self).__init__()
        print("fifth (after)")

Fifth()

它是如何运行的?fifth()的实例如下所示。每一步从一个类到另一个类,其中添加了超函数。

1.) print("fifth (before)")
2.) super()>[Second, Third, Fourth] (Left to right)
3.) print("second (before)")
4.) super()> First (First is the Parent which inherit from object)

父母已经找到了,会继续到第三和第四!!

5.) print("third (before)")
6.) super()> First (Parent class)
7.) print ("Fourth (before)")
8.) super()> First (Parent class)

现在所有带有super()的类都已经被访问了!父类已经找到并执行,现在它继续在继承中解箱函数以完成代码。

9.) print("first") (Parent)
10.) print ("Fourth (after)") (Class Fourth un-box)
11.) print("third (after)") (Class Third un-box)
12.) print("second (after)") (Class Second un-box)
13.) print("fifth (after)") (Class Fifth un-box)
14.) Fifth() executed

以上方案的成果:

fifth (before)
second (before
third (before)
fourth (before)
first
fourth (after)
third (after)
second (after)
fifth (after)

对我来说,添加super()可以让我更清楚地看到python如何执行我的代码,并确保继承可以访问我想要的方法。