在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
实例时执行ParentB
的set_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/(真的 - 你不必全部理解 - 它处理了很多极端情况 - 只需了解它的“感觉”即可。)
我有一个关于子 class 的实例化过程的问题,该子 class 从父 class A 没有 arg 和父 class B 分别带有 kwargs 的多重继承。
在下面的代码中,我不知道为什么在创建Child
实例时执行ParentB
的set_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/(真的 - 你不必全部理解 - 它处理了很多极端情况 - 只需了解它的“感觉”即可。)