From: 使用元类app
与静态语言最大的不一样,就是函数和类的定义,不是编译时定义的,而是运行时动态建立的。函数
咱们说class的定义是运行时动态建立的;测试
而建立class的方法就是使用type()
函数。spa
type()
函数既能够返回一个对象的类型,又能够建立出新的类型。code
问题来了:type建立了一个类?如何理解。如下即是一个 “动态建立” 的过程。对象
>>> def fn(self, name='world'): # 先定义函数 ... print('Hello, %s.' % name) ... >>> Hello = type('Hello', (object,), dict(hello=fn)) # 建立Hello class
>>> h = Hello() >>> h.hello() Hello, world. >>> print(type(Hello)) <class 'type'> >>> print(type(h)) <class '__main__.Hello'>
要控制类的建立行为,还能够使用metaclass。blog
metaclass,直译为元类,简单的解释就是:先定义metaclass,就能够建立类,最后建立实例。get
因此,metaclass容许你建立类或者修改类。换句话说,你能够把“类”当作是metaclass建立出来的“实例”。编译
metaclass是Python面向对象里最难理解,也是最难使用的魔术代码。模板
正常状况下,你不会碰到须要使用metaclass的状况。
[实验]:经过metaclass给咱们自定义的MyList增长一个add
方法。
定义ListMetaclass
,按照默认习惯,metaclass的类名老是以Metaclass结尾,以便清楚地表示这是一个metaclass:
# metaclass是类的模板,因此必须从`type`类型派生: classListMetaclass(type): def __new__(cls, name, bases, attrs): attrs['add'] = lambda self, value: self.append(value) # 添加了add方法 return type.__new__(cls, name, bases, attrs)
有了ListMetaclass,咱们在定义类的时候还要指示使用ListMetaclass来定制类,传入关键字参数metaclass
:
class MyList(list, metaclass=ListMetaclass): pass
测试了一下,MyList能够调用add方法。
>>> L = MyList() >>> L.add(1) >> L [1]
直接在MyList
定义中写上add()
方法不是更简单吗?正常状况下,确实应该直接写,经过metaclass修改纯属变态。
可是,总会遇到须要经过metaclass修改类定义的。ORM就是一个典型的例子。
/* implement */
End.