如何:使用不同的参数安全地调用超级构造函数

How to: safely call super constructors with different arguments

我已经看到 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 调用中传递这些论点,以一种变得透明的方式。

你他们不要多次调用你的祖先类:你让语言运行时为你做。

你的代码应该这样写:

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 方法解析顺序机制,并指向有关它们的官方文档: