2017-05-26 55 views
0

我试图让我的头绕着元类,但我仍然不能真正理解它的概念。了解Python中的元类

据我所知:

任何类本身类型的“类型”的一个实例 - 因此“呼叫”一类的只是调用它的类中的方法__call__ - 这恰好是类型的__call__。的type.__call__的效果是完全:上类似的代码:

A类: 通 B = A()

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

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

  1. 它调用A.__new__ - 以伪代码的形式,我们可以编写instance = A.__new__(cls)作为运行的代码。

3.That返回 “A” 类的一个实例

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

但现在考虑下面的代码:

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 

所以,按照我的理解,这是步骤的顺序:

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

  2. 由于MetaOne继承了类型,因此会调用__call__类型为Spam的方法作为第一个参数。

此后在MetaOne类的__new__方法调用的土地了,但它应该包含Spam作为第一个参数。

从哪里MetaOne类的meta争论进入画面。

请帮我理解。

回答

0

由于垃圾邮件是)MetaOne的一个实例,主叫X =垃圾邮件(将试图 呼叫MetaOne类的__call__方法,该方法是不存在。

这就是你的困惑的soruce - 元类的__call__(或__new____init__)是当你创建类的实例一般叫。

另外,由于是为MetaOne没有__call__方法,通常的继承规则:用在MetaOne的超类的__call__方法(它是type.__call__

元类被调用__new____init__方法时,类本体本身被执行(如你在你的例子中看到的,元类“__new__”中的“打印”出现在“制作实例”文本之前)。

当创建的Span自身的实例,元类方法__new____init__不叫 - 元类__call__被称为 - 这是执行类的(跨度的)__new____init__。换句话说:元类__call__负责调用“普通”类__new____init__

由于MetaOne从类型继承它将调用 型类的呼叫方法与垃圾邮件作为第一个参数。

它,但你再没打印语句“视图”这样的情况:如果我粘贴在ineractive控制台,在这一点上打印

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__") 

At meta __new__ 

然后,正在进行的交互式会话:

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

并且额外的思想扭曲的事情是:“type是类型自己的元类”:这意味着type__call__也负责在元类本身上运行__new____init__方法,当一个新的(非元)类体被执行。