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就是标准库定义的一个元类,而且也可以自己定义元类:
一般情况下,如果你要用自定义 metaclass 的话,该类需要继承自 type,而且通常会重写 type 的 __new__ 方法来控制创建过程,对自定义类调用type() 函数的结果是
isinstance() 函数用来判断派生关系,type() 函数可以用来查看一个类型或变量的类型。
当用户定义一个类的时候,Python 解释器首先在当前类的定义中查找 metaclass,如果没有找到,就继续在基类中查找 metaclass,找到了,就使用它创建类,也就是说,metaclass 可以隐式地继承到子类,但子类自己却感觉不到。
一个类的定义方式可以是这样的:
这™不就是把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的定义:
这个定义其实是被解释器解释为
在创建类的过程,我们可以在__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。
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。
相关文章推荐
- python 字符串转换,mysql插入带引号字符串,获取html纯文字
- Python资料合集
- Python-BlogServer博客-Django博客效果
- Python--Cmd窗口运行Python时提示Fatal Python error: Py_Initialize: can't initialize sys standard streams LookupError: unknown encoding: cp65001
- Python线程的两种创建方法
- python 学习备忘9.2
- Python的Threading模块的Thread对象的join方法
- Python视频教程
- Building Python 2.7.10 with Visual Studio 2010 or 2015 - Google Chrome
- python webdriver API
- "Python"学习笔记(一)
- python 实现定时循环触发某个方法
- 当Python和R遇上北京二手房(上)
- python初学 汉诺塔攻略实现
- 在ArcGIS中创建Python工具(二)
- Python核心编程-练习
- Python游戏服务器开发日记(六) 解决GIL难题!——Python再认识
- Python游戏服务器开发日记(五)skynet_messagequeue和skynet_timer
- python做全文检索引擎
- python实现去除文本中的中文符号和英文符号