元类的__new__和__init__的参数 [英] Arguments of __new__ and __init__ for metaclasses
问题描述
在元类中重写new
和init
时,我对方法调用顺序和不同的参数感到惊讶.请考虑以下内容:
I am a bit surprised by the method call order and the different arguments when overriding new
and init
in a metaclass. Consider the following:
class AT(type):
def __new__(mcs, name, bases, dct):
print(f"Name as received in new: {name}")
return super().__new__(mcs, name + 'HELLO', bases + (list,), dct)
def __init__(cls, name, bases, dct):
print(f"Name as received in init: {name}")
pass
class A(metaclass=AT):
pass
A.__name__
输出为:
Name as received in new: A
Name as received in init: A
'AHELLO'
简而言之,我希望init
接收到带有参数name
的AHELLO
.
In short I would have expected init
to receive AHELLO
with the argument name
.
我以为__init__
是由super().__new__
调用的:如果未在覆盖的__new__
中进行该调用,则不会调用我的__init__
.
I imagined that __init__
was called by super().__new__
: if the call is not done in the overridden __new__
then my __init__
is not called.
有人可以澄清在这种情况下如何调用__init__
吗?
Could someone clarify how __init__
is called in this case?
作为参考,我的用例是,我想通过仅提供一个基本"类(而不是元组)来简化类的创建,在特殊情况下,我在运行时将其添加到__new__
:
For information my use case for this is that I wanted to make creation of classes, in a special case, easier at runtime by providing only a single "base" class (and not a tuple), I then added this code in __new__
:
if not isinstance(bases, tuple):
bases = (bases, )
但是,我发现我还需要在__init__
中添加它.
however, I found out that I also need to add it in __init__
.
推荐答案
您的__init__
方法显然被调用了,其原因是因为您的__new__
方法正在返回类的实例.
Your __init__
method is obviously called and the reason for that is because your __new__
method is returning an instance of your class.
来自 https://docs.python.org/3/reference/datamodel.html#object.新 :
如果
__new__()
返回cls的实例,则将像__init__(self[, ...])
一样调用新实例的__init__()
方法,其中self是新实例,其余参数与传递给__new__()
的参数相同.
If
__new__()
returns an instance of cls, then the new instance’s__init__()
method will be invoked like__init__(self[, ...])
, where self is the new instance and the remaining arguments are the same as were passed to__new__()
.
如您所见,传递给__init__
的参数是传递给__new__
方法的调用者的参数,而不是使用super
进行调用时传递的参数.有点含糊,但是如果您仔细阅读,那就意味着什么.
As you can see the arguments passed to __init__
are those passed to __new__
method's caller not when you call it using super
. It's a little bit vague but that's what it means if you read it closely.
关于其余部分,它可以按预期工作:
And regarding the rest it works just as expected:
In [10]: A.__bases__
Out[10]: (list,)
In [11]: a = A()
In [12]: a.__class__.__bases__
Out[12]: (list,)
这篇关于元类的__new__和__init__的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!