了解Python中的元类 [英] Understanding metaclasses in 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.
- 它调用
A.__new__
-使用伪代码,我们可以将instance = A.__new__(cls)
编写为运行内容.
- It calls the
A.__new__
- in pseudocode we could writeinstance = 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:
-
由于垃圾邮件是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 .
由于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屋!