道生一,一生二,二生三,三生万物。
Python中的“道”是type,“一”就是metaclass。“二”是class,“三”是实例,那万物自然是各种属性方法功能了。
type函数相当于类的工厂,metaclass就是生产出来的第一台原型机。
1.type函数
函数可以查看一个类型或变量的类型。比如Hello是一个class,h是Hello的实例。那么:
因为Python是动态语言,甚至可以通过type函数创建出Hello类。
创建一个class对象,type()函数依次传入3个参数:
class的名称
继承的父类集合,注意Python支持多重继承,如果只有一个父类,需要使用tuple的单元素写法。
class的方法名称与函数绑定。
2.metaclass元类
metaclass直译为元类,按照定义的顺序就是先定义元类,再定义类,最后创建实例。直接来书metaclass允许创建类或者修改类。
定义metaclass的类名总是以Metaclass结尾:
定义了元类之后,就可以使用元类来定制类。传入关键字 :
Python解释器在创建MyList时,要通过 来创建,我们可以修改类的定义,比如加上新的方法,然后还是返回修改后的定义。
方法接受到的参数依次是:
当前准备创建的类的对象
类的名字
类继承的父类集合
类的方法集合
这样实际上给MyList添加了一个add方法,普通的list就没有add方法。正常情况下直接在MyList的定义中加上add方法确实更简单,但是在某些特殊情况下metaclass是有用的。
3.metaclass例子:ORM
ORM是对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样不用直接操作SQL语句。
要编写一个ORM框架,所有的类只能动态定义。
先看下需求:考虑使用者使用ORM框架,想定义一个User类来操作对应的数据库表User我们会希望他写出如下代码:
其中父类Model属性类型StringField、IntegerField是由ORM框架提供的,剩下的方法比如save()都是由metaclass自动完成的。下面我们就来实现简单的ORM框架。
定义Field类
在Field的基础上,定义各种类型的Field,如StringField,IntegerField:
编写ModelMetaclass
编写基类Model
ORM的说明
当用户定义一个 时,Python解释器首先在User的定义中查找metaclass,然后在Model中查找metaclass。使用ModelMetaclass来创建User类。
在ModelMetaclass中做了如下工作:
排除掉对Model类的修改
在当前类中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个 的dict中,同时从类属性中删除该Field属性。否则会导致实例的属性会遮盖类的同名属性。
把表名保存到 中,这里简化为表名默认为类名。
然后在Model类中就可以定义各种操作数据库的方法了,这里实现了save()方法,把一个实例保存到数据库中。因为有表名,属性到字段的映射和属性值的集合,因此可以创建INSERT语句了。
调用时就直接如下使用即可。