了解Python中的元类 [英] Understanding metaclasses in Python

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

问题描述

我试图绕过元类,但是我仍然无法真正理解它的概念.

I am trying to get my head around metaclass but i still can't really get the concept of it.

据我所知:

任何类本身都是类型"类型的实例-因此,调用"一个类只是在其类上调用方法__call__-恰好是类型的__call__. type.__call__的作用完全是:在类似以下代码上:

Any class is itself an instance of type "type" - therefore "calling" a class just calls the method __call__ on its class - which happens to be type's __call__. The effect of type.__call__ is exactly: on code like:

A级: 经过 b = A()

class A: pass b = A()

我在这里知道的步骤顺序是:

The sequence of steps i know here is:

1. type.__call__接收类A本身作为其第一个参数.

1.type.__call__ receives the class A itself as its first parameter.

  1. 它调用A.__new__-使用伪代码,我们可以将instance = A.__new__(cls)编写为运行内容.
  1. It calls the A.__new__ - in pseudocode we could write instance = A.__new__(cls) as what runs.

3.返回"A"类的实例

3.That returns an instance of the "A" class

4.然后在实例上调用__init__(instance.__init__()) ...并返回该实例,返回实例

4.Then it calls __init__ on the instance(instance.__init__()) ...and returns that instance return instance

但是现在考虑以下代码:

But now consider the below code:

class MetaOne(type):
    def __new__(meta, classname, supers, classdict):
        print('In MetaOne.new:', meta, classname, supers, classdict, sep='\n...')
        return type.__new__(meta, classname, supers, classdict)

class Eggs:
    pass

print('making class')

class Spam(Eggs, metaclass=MetaOne): 
    data = 1 
    def meth(self, arg): 
        return self.data + arg

print('making instance')
X = Spam()
print('data:', X.data, X.meth(2))

此脚本的输出如下:

making class
In MetaOne.new:
...<class '__main__.MetaOne'>
...Spam
...(<class '__main__.Eggs'>,)
...{'__qualname__': 'Spam', '__module__': '__main__', 'meth': <function Spam.met
h at 0x00000000010C1D08>, 'data': 1}
making instance
data: 1 3

据我所知,这是步骤的顺序:

So as per my understanding this is the sequence of steps:

  1. 由于垃圾邮件是MetaOne的实例,因此调用X = Spam()会尝试调用不存在的MetaOne类的__call__方法.

  1. Since Spam is an instance of MetaOne, calling X = Spam() would try to call the __call__ method of MetaOne class which is not there .

由于MetaOne从类型继承,因此它将调用类型类的__call__方法,并以Spam作为第一个参数.

Since MetaOne inherits from type it would call the __call__ method of type class with Spam as the first argument.

此后,调用会到达MetaOne类的__new__方法中,但它应包含Spam作为第一个参数.

After that the call lands up in the __new__ method of MetaOne class but it should contain Spam as the first param.

MetaOne类的meta自变量从何而来.

From where does meta argument of MetaOne class come into picture.

请帮助我理解.

推荐答案

由于垃圾邮件是MetaOne的实例,因此调用X = Spam()会尝试 调用不存在的MetaOne类的__call__方法.

Since Spam is an instance of MetaOne, calling X = Spam() would try to call the __call__ method of MetaOne class which is not there .

这就是您困惑的源头-创建类的普通实例时,不会调用元类的__call__(或__new____init__).

That is the soruce of your confusion - the __call__ (or __new__ and __init__) of the metaclass is not called when you create ordinary instances of the class.

此外,由于没有用于MetaOne__call__方法,因此适用通常的继承规则:使用MetaOne的超类上的__call__方法(它是type.__call__)

Also, since there is no __call__ method for MetaOne, the usual inheritance rules apply: the __call__ method on MetaOne's superclass is used (and it is type.__call__)

执行类主体本身时将调用元类的__new____init__方法(如您在示例中所看到的,元类的__new__中的打印"出现在生成实例"之前文本).

The metaclass' __new__ and __init__ methods are invoked when the class body itself is executed (as you can see in your example, the "print" in the metaclass' __new__ shows up before the "making instance" text).

在创建Span本身的实例时,不调用元类方法__new____init__-调用元类__call__-它是执行类的(Span)__new__的对象,并且__init__.换句话说:元类__call__负责调用普通"类的__new____init__.

When creating an instance of Span itself, the metaclass methods __new__ and __init__ are not called - the metaclass __call__ is called - and it is that that executes the class's(Span's) __new__ and __init__. In other words: the metaclass __call__ is responsible for calling the "ordinary" class's __new__ and __init__.

由于MetaOne从类型继承,它将调用 call 方法 输入垃圾邮件作为第一个参数的类.

Since MetaOne inherits from type it would call the call method of type class with Spam as the first argument.

确实如此,但是您没有打印出任何语句来查看"这种情况:

And it does, but you made no print statements to "view" this happening:

class MyMeta(type):
    def __new__(metacls, name, bases, namespace):
        print("At meta __new__")
        return super().__new__(metacls, name, bases, namespace)   
    def __call__(cls, *args, **kwd):
        print ("at meta __call__")
        return super().__call__(*args, **kwd)

def Egg(metaclass=MyMeta):
    def __new__(cls):
        print("at class __new__")

如果我将其粘贴在非活动控制台上,此时它将打印:

If I paste this at the ineractive console, at this point it prints:

At meta __new__

然后,进行交互式会话:

Then, going on the interactive session:

In [4]: fried = Egg()
at meta __call__
at class __new__

令人费解的是:类型是类型自己的元类":表示type__call__还负责在元类本身上运行__new____init__方法,当执行新的(非元数据)类主体时.

And the extra mind-twisting thing is that: "type is type's own metaclass": meaning that type's __call__ is also responsible for running the __new__ and __init__ methods on the metaclass itself, when a new (non-meta) class body is executed.

这篇关于了解Python中的元类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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