如何:安全地调用具有不同参数的超级构造函数
Posted
技术标签:
【中文标题】如何:安全地调用具有不同参数的超级构造函数【英文标题】:How to: safely call super constructors with different arguments 【发布时间】:2022-01-17 01:58:09 【问题描述】:我看到super().__init__(*args)
曾经安全地调用超级构造函数(以一种不会失败菱形继承的方式)。但是我找不到以这种方式调用具有不同参数的不同超级构造函数的方法。
这是一个说明问题的示例。
from typing import TypeVar, Generic
X = TypeVar("X")
Y = TypeVar("Y")
class Base:
def __init__(self):
pass
class Left(Base, Generic[X]):
def __init__(self, x:X):
super().__init__()
self.lft = x
class TopRight(Base, Generic[Y]):
def __init__(self, y:Y):
super().__init__()
self.rgh = y
class BottomRight(TopRight[Y], Generic[Y]):
def __init__(self, y:Y):
super().__init__(y + y)
class Root(Left[X], BottomRight[Y], Generic[X, Y]):
def __init__(self, x:X, y:Y):
pass #issue here
#does not work
#super().__init__(x)
#super().__init__(y)
#calls base twice
#Left[X].__init__(x)
#BottomRight[Y].__init__(y)
如何分别安全地呼叫Left.__init__(x)
和BottomRight.__init__(y)
?
【问题讨论】:
一方面,super().__init__()
调用Left
和TopRight
是不行的,因为它们甚至不尊重Base
的签名。您可以传入 int
或将默认参数添加到 Base
以解决该问题。
我认为简短的回答是不要做这样的事情。像 Java 这样的东西不支持菱形继承是有原因的。
感谢您指出示例代码的问题,此外,多重继承仍然有用,特别是考虑到 python 的打字系统。
现在Base
有语法错误(你忘了pass
)
【参考方案1】:
问题在于,要以协作形式使用,中间类必须接受不是“针对”它们的参数,并通过自己的super
调用以透明的方式传递这些参数。
你他们不要多次调用你的祖先类:你让语言运行时为你做这件事。
你的代码应该写成:
from typing import Generic, TypeVar
X = TypeVar("X")
Y = TypeVar("Y")
class Base:
def __init__(self):
pass
class Left(Base, Generic[X]):
def __init__(self, x:X, **kwargs):
super().__init__(**kwargs)
self.lft = x
class TopRight(Base, Generic[Y]):
def __init__(self, y:Y, **kwargs):
super().__init__(**kwargs)
self.rgh = y
class BottomRight(TopRight[Y], Generic[Y]):
def __init__(self, y:Y, **kwargs): # <- when this is executed, "y" is extracted from kwargs
super().__init__(y=y + y, **kwargs) # <- "x" remains in kwargs, but this class does not have to care about it.
class Root(Left[X], BottomRight[Y], Generic[X, Y]):
def __init__(self, x:X, y:Y):
super().__init__(x=x, y=y) # <- will traverse all superclasses, "Generic" being last
另外,请注意,根据您项目的目的和最终的复杂性,这些类型注释可能不会给您带来任何好处,反而会增加代码的复杂性,否则会变得微不足道。它们在 Python 项目中并不总是有好处,尽管由于工具(即 IDE)的情况,可能会推荐它们。
另外,查看几天前类似的答案,我是否详细介绍了 Python 方法解析顺序机制,并指向它们的官方文档:In multiple inheritance in Python, init of parent class A and B is done at the same time?
【讨论】:
打败我。很不错!尤其是最后一点。鸭子打字在大多数时候都很棒。 不应该打电话给Root
是super().__init__(x=x, y=y)
吗?
确实如此。否则 kwargs 不会选择它们
也缺少括号。 super()
与 super
@MadPhysicist 我冒昧添加了括号以上是关于如何:安全地调用具有不同参数的超级构造函数的主要内容,如果未能解决你的问题,请参考以下文章