在Python中的多重继承中,parent class A和B的init是同时完成的?

In multiple inheritance in Python, init of parent class A and B is done at the same time?

我有一个关于子 class 的实例化过程的问题,该子 class 从父 class A 没有 arg 和父 class B 分别带有 kwargs 的多重继承。

在下面的代码中,我不知道为什么在创建Child实例时执行ParentBset_kwargs()方法而ParentA被初始化。

(特别是,为什么结果显示Child receive {}?我怎样才能避免这个结果?)

任何帮助将不胜感激。

谢谢!

class GrandParent:
    def __init__(self):
        print(f"{self.__class__.__name__} initialized")

class ParentA(GrandParent):
    def __init__(self):
        super().__init__()

class ParentB(GrandParent):
    def __init__(self, **kwargs):
        super().__init__()
        self.set_kwargs(**kwargs)
        
    def set_kwargs(self, **kwargs):
        print(f"{self.__class__.__name__} receive {kwargs}")
        self.content = kwargs.get('content')

class Child(ParentA, ParentB):
    def __init__(self, **kwargs):
        ParentA.__init__(self)
        ParentB.__init__(self, **kwargs)

c = Child(content = 3)

结果:

Child initialized
Child receive {}
Child initialized
Child receive {'content': 3}

对于大多数多重继承的情况,您会希望 superclass 方法由 Python 运行time 本身按顺序调用。

为此,只需调用 super() 的 return 中的目标方法即可。

在您的情况下,最派生的 class' init 应如下所示:

class Child(ParentA, ParentB):
    def __init__(self, **kwargs):
        super().__init__(self, **kwargs)

并且所有三个超级classes __init__ 方法都将是正确的运行。请注意,要实现这一点,必须构建它们以便能够在这样的 class 层次结构中协同工作 - 为此需要两件事:一个是任何 super[=38 中的每个方法=]es 将自己置于 class 到 super().method()- 这在您的代码中是可以的。另一个是,如果要将参数传递给这些方法,并非所有 classes 都知道,每个 superclass 中的方法应该只提取它知道的参数,并传递其余的它自己的 super() 调用中的参数。

所以正确的形式实际上是:

class GrandParent:
    def __init__(self):
        print(f"{self.__class__.__name__} initialized")

class ParentA(GrandParent):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

class ParentB(GrandParent):
    def __init__(self, **kwargs):
        content = kwargs.pop('content')
        super().__init__(**kwargs)
        self.set_kwargs(content)
        
    def set_kwargs(self, content):
        print(f"{self.__class__.__name__} receive {content}")
        self.content = content

class Child(ParentA, ParentB):
    def __init__(self, **kwargs):
        super.__init__(**kwargs)

c = Child(content = 3)

下一个super()调用时调用的class是在创建class多个parents时由Python计算得出的- 因此,即使“ParentA”和“ParentB”都直接继承自祖父母,当 super() 调用链从“Child”冒泡时,Python 将从内部“知道” “ParentA”下一个 superclass 是“ClassB”并改为调用它的 __init__

查找“方法解析顺序”的算法非常复杂,即使不是全部,它也能“按预期工作”用于大多数用例。可以在这里找到它的确切描述:https://www.python.org/download/releases/2.3/mro/(真的 - 你不必全部理解 - 它处理了很多极端情况 - 只需了解它的“感觉”即可。)