多重继承中super().__new__和super().__init__的混淆动作

The confusing action of super().__new__ and super().__init__ in multiple inheritance

创建一个 son class 其中有两个 parents:

class mon():
    def __new__(cls):
        print("i am in mon's new")
        return super().__new__(cls)
    def __init__(self):
        print("i am in mon's init")
        super().__init__()


class far():
    def __new__(cls):
        print("i am in far's new")
        return super().__new__(cls)
    def __init__(self):
        print("i am in far's init")


class son(mon,far):
    def __init__(self):
        super().__init__()

初始化 son class 检查发生了什么。
super().__init__() in son class会调用mon中的__init__方法,[=24=中__init__之前执行的__new__方法],super().__new__(cls) in mon ,让代码跳转到far class,__new__方法在__init__ in [=30=之前执行], 代码跳回 mon 打印 i am in mon's init 并跳转到 far 打印 i am in far's init ,所以我们得到下面的输出。

son_instance = son()
i am in mon's new
i am in far's new
i am in mon's init
i am in far's init

问题 1:

初始化son class时如何重写三个class结构得到如下输出?

son_instance = son()
i am in mon's new
i am in mon's init
i am in far's new
i am in far's init

删除far中的语句 class:

return super().__new__(cls)

整个三个class如下:

class mon():
    def __new__(cls):
        print("i am in mon's new")
        return super().__new__(cls)
    def __init__(self):
        print("i am in mon's init")
        super().__init__()


class far():
    def __new__(cls):
        print("i am in far's new")

class son(mon,far):
    def __init__(self):
        super().__init__()

再次初始化 son class。

x=son()
i am in mon's new
i am in far's new

问题 2:
为什么代码不能跳回mon class?为什么不能得到下面的输出?

x=son()
i am in mon's new
i am in far's new
i am in mon's init

如果farclass中没有return super().__new__(cls),则只对farclass中的__init__生效,没有__init__ far class 中的方法,为什么它导致不调用 mon class 中的 __init__ 方法?

让我试着一一回答你的两个问题。

How can rewrite the three class structure to get such output as below when to initialize son class?

你不能。您的代码需要先使用 __new__ 方法创建新实例,然后才能开始使用 __init__ 方法初始化实例。如果您希望 运行 的行为以其他顺序进行,则需要在其他地方进行。您无法调整继承层次结构来使其正常工作。

Why the code can't jump back to mon class ?Why can't get the following output?

您的代码无法正常工作,因为 far.__new__ 已损坏(可能是因为您在删除 __init__ 方法时过于热心并删除了额外的一行)。 __new__ 方法没有 return 任何东西,相当于 returning None。如果 __new__ 方法没有 return 正在创建的 class 的实例,则永远不会调用 __init__ 方法。如果您通过在 return super().__new__(cls) 中重新添加来修复 __new__ 方法,您将获得您期望的输出。

即使 far class 本身没有 __init__ 方法,也会发生这种情况。外部代码(在本例中为 type.__call__)不知道整个继承层次结构并依次调用每个函数。它只调用正在创建的 class 上的方法,并且它相信如果合适的话,实现将调用函数的父 class 版本。如果 son.__new__(继承)returns None 就像 far.__new__ 被破坏时那样,那么 son.__init__ 将不会像以前那样被调用__new__ 方法正常工作。

这是type.call的一个非常近似的纯Python版本(实际版本是用C实现的):

def __call__(cls, *args):   # this is in a metaclass, so I use cls instead of self
    obj = cls.__new__(*args)
    if isinstance(obj, cls):
        obj.__init__(*args)
    return obj

我遗漏了很多额外的东西,例如 type(obj) 如何让您获取现有实例的类型,而不是创建新类型。但是,当涉及到常规实例创建时,行为如图所示。

您可以在 the Python source code repository, if you want. The section where the C version of type.__call__ (called type_call) checks if the object returned from cls.__new__ is of the right type is here 中阅读完整的详细信息(C 语言)。