元类的__new__和__init__的参数 [英] Arguments of __new__ and __init__ for metaclasses

查看:93
本文介绍了元类的__new__和__init__的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在元类中重写newinit时,我对方法调用顺序和不同的参数感到惊讶.请考虑以下内容:

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接收到带有参数nameAHELLO.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆