道生一,一生二,二生三,三生万物。

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语句了。

调用时就直接如下使用即可。