使用元类
type()
动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。
比方说我们要定义一个Hello的class,就写一个hello.py模块:
class Hello(object):
def hello(self,name='world'):
print('Hello,%s'%name)
然后创造实例进行调用:
>>> h = Hello()
>>> h.hello()
Hello,world
>>> print(type(Hello))
<class 'type'>
>>> print(type(h))
<class '__main__.Hello'>
type()函数可以查看一个类型或变量的类型,Hello是一个class,它的类型就是type,而h是一个实例,它的类型就是class Hello。我们说class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。
通过type()函数创建的类和直接写class创建的类效果是相同的,在写class定义的时候,Python解释器只是扫描一下定义的语法,然后根据type()创建出class。
metaclass
如果我们想要控制类的创建,还可以使用metaclass。metaclass,直译为元类,简单的解释就是:当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。但是如果我们想创建出类呢?那就是先定义metaclass,就可以创建类,最后创建实例。可以把类看成是metaclass创建出来的“实例”。
我们先看一个简单的例子,这个metaclass可以给我们自定义的MyList增加一个add方法:
>>> class ListMetaclass(type):
def __new__(cls,name,bases,attrs):
attrs['add'] = lambda self,value:self.append(value)
return type.__new__(cls,name,bases,attrs)
然后使用ListMetaclass来定制类,传入关键字参数metaclass:
class MyList(list, metaclass=ListMetaclass):
pass
当我们传入关键字参数metaclass时,魔术就生效了,它指示Python解释器在创建MyList时,要通过ListMetaclass.new()来创建,在此,我们可以修改类的定义,比如,加上新的方法,然后,返回修改后的定义。
测试一下MyList是否可以调用add()方法:
>>> L = MyList()
>>> L.add(1)
>>> L
[1]
而普通的list则没有add()方法:
>>> L = list()
>>> L.add(1)
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
L.add(1)
AttributeError: 'list' object has no attribute 'add'
__new__函数里可以接受的参数为
- 当前准备创建的类的对象;
- 类的名字;
- 类继承的父类集合;
- 类的方法集合。
这种强大的功能使用起来务必小心。