多重继承中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
如果far
class中没有return super().__new__(cls)
,则只对far
class中的__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 语言)。
创建一个 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
如果far
class中没有return super().__new__(cls)
,则只对far
class中的__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 语言)。