您的位置:首页 > 编程语言 > Python开发

Python中的元类(metaclass)

2015-09-03 01:26 761 查看
在wiki上面,metaclass是这样定义的:In object-oriented programming, a metaclass is a class whose instances are classes.

Python中对象模型如下图:



其中,实线表示 is-kind-of(派生)的关系,虚线表示 is-instance-of(实例化)的关系。

可以看出,object 是其他所有类的基类。

这里并不完整,因为元类并不只有type一个,比如enum.EnumMeta就是标准库定义的一个元类,而且也可以自己定义元类:



Python中metaclass的原理

metaclass的原理其实是这样的:当定义好类之后,创建类的时候其实是调用了 type 的 __new__ 方法为这个类分配内存空间,然后再调用type的__init__ 方法初始化。所以 metaclass 的所有 magic 其实就在这个 __new__ 方法里面了。

一般情况下,如果你要用自定义 metaclass 的话,该类需要继承自 type,而且通常会重写 type 的 __new__ 方法来控制创建过程,对自定义类调用type() 函数的结果是
<class 'type'>


isinstance() 函数用来判断派生关系,type() 函数可以用来查看一个类型或变量的类型。

当用户定义一个类的时候,Python 解释器首先在当前类的定义中查找 metaclass,如果没有找到,就继续在基类中查找 metaclass,找到了,就使用它创建类,也就是说,metaclass 可以隐式地继承到子类,但子类自己却感觉不到。

一个类的定义方式可以是这样的:

class C(object, metaclass=MyMetaClass):
......


__new__,__init__,metaclass之间的关系

class的__new__ 是用来构建object的,__init__是用来在构建好object后进行初始化的,__new__ 第一个参数是class本身,__init__的第一个参数是self,self就是已经构建好的object啊,其他参数相同。

这™不就是把c++里构造函数的功能分开了嘛!然而我觉得普通类的__new__ 并没什么用,又不需要和c++似的去操纵内存,不过是一层一层调用基类的__new__ 。

关键是Python还有个metaclass啊,用来构建class,这些metaclass的基类是type。metaclass的__init__反而不重要了,只要构造出class来就行,不需要初始化。

metaclass的__new__(cls, name, bases, attrs)是长这个样子的,其中:

cls:指的是metaclass本身

name:class的名字,是一个字符串,也就是我们通常用 类名.__name__ 获得的那个

bases:class的基类组成的元组

attrs:class的属性组成的dict

什么时候构建类呢?就在类定义的时候,比如下面class X的定义:

class Meta(type):
def __new__(cls, name, bases, attrs):
print('in Meta')
return type.__new__(cls, name, bases, attrs)

class X(object, metaclass=Meta):
pass
# 输出in Meta


这个定义其实是被解释器解释为
X = Meta('X', (object,), {})
的,Meta既然是metaclass,那也是class啊,所以先调用了__new__来构建X,然后调用__init__来初始化X。所以打印出了“in Meta”。

在创建类的过程,我们可以在__new__里面修改 name,bases,attrs 的值来达到我们的功能。这里常用的配合方法是 getattr 和 setattr。

另外还有一个限制,the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: