转载 http://ju.outofmemory.cn/entry/105710
什么是 metaclass ?
In object-oriented programming, a metaclass is a class whose instances are
Wikipedia Metaclass
classes. Just as an ordinary class defines the behavior of certain objects, a
metaclass defines the behavior of certain classes and their instances.
简单的说, metaclass 就是 class 类型对象的 class, metaclass 的实例对象是 class 类型对象.
metaclass 能用来做什么 ?
我们就可以用 metaclass 来动态生成或者更改 class 的定义.
下面分别是通过传统 class 方式以及 metaclass 动态定义类 A
class A(object):
a = 'I am a string.'
A = type('A', (object,), {'a': 'I am a string.'})
上面我们通过type
类的实例化来生成类A
, 如果我们想自定义类的生成, 我们可以以type
类为基 类派生出自定义的 metaclass.
注: 本文所有代码在 python2.6 下能执行通过, 不能确保在 python3 下无误.
继承type
类实现 metaclass
我们可以从type
类派生出新的 metaclass, 然后通过重新实现__new__
, __init__
, __call__
来实现类或者类实例的生成.
class Meta(type):
def __call__(self):
print 'Enter Meta.__call__: ', self
obj = type.__call__(self)
print 'Exit Meta.__call__: ', obj
return obj
def __new__(metacls, name, bases, dictionary):
print 'Enter Meta.__new__:', metacls, name, bases, dictionary
newClass = type.__new__(metacls, name, bases, dictionary)
print 'Exit Meta.__new__: ', newClass
return newClass
def __init__(cls, name, bases, dictionary):
print 'Enter Meta.__init__: ', cls, name, bases, dictionary
super(Meta, cls).__init__(name, bases, dictionary)
print 'Exit Meta.__init__'
print 'Create class A'
A = Meta('A', (object,), {})
print
print 'Create instance of class A'
A()
当我们运行上述的python文件, 会得到下面的输出结果:
$ python meta.py
Create class A
Enter Meta.__new__: <class '__main__.Meta'> A (<type 'object'>,) {}
Exit Meta.__new__: <class '__main__.A'>
Enter Meta.__init__: <class '__main__.A'> A (<type 'object'>,) {}
Exit Meta.__init__
Create instance of class A
Enter Meta.__call__: <class '__main__.A'>
Exit Meta.__call__: <__main__.A object at 0xb76a9ccc>
$
通过上面的输出结果, 我们可以看出:
Meta.__new__
是用来生成类A
的类型对象, 我们可以在调用type.__new__
之前更改dictionary
变量来增加/修改/删除新生成类A
的成员变量/方法.Meta.__init__
是在生成类A
的类型对象后被调用类进行类A
的初始化. 第一个参数cls
是已经生成的类A
类型对象, 可以通过直接修改cls
来修改类的定义, 例如增加成员变量.Meta.__call__
是在生成类A
的实例对象时被调用的, 通过调用type.__call__
可以 生成该实例对象obj
, 之后我们可以直接修改obj
来实现实例对象的自定义.
如何使用 metaclass ?
- 我们可以直接调用
type
或者Meta
来动态生成新的类型对象A
:
A = Meta('A', (object,), {})
- 在定义类的时候, 重新指定该类的
__metaclass__
属性为Meta
:
class A(object):
__metaclass__ = Meta
# other member variables/methods definition
注意: 定义__metaclass__
生成的类A
会增加_A__metaclass
成员变量, 在某些场景下需要 了解到这个区别.
函数方式定义类的 metaclass
类的__metaclass__
可以是一个type
类型的子类, 也可以是一个函数, 该函数接受三个参数:
- name: 字符串类型, 表示新生成类型对象的名称
- bases: tuple类型, 新生成类型对象的父类列表
- properties: 字典类型, 新生成类型对象的属性
该函数必须返回新生成的类型对象. 下面例子是一个简单实现:
def meta_func(name, bases, properties):
# you can modify bases, properties here to overide class creation
return type(name, bases, properties)
class A(object):
__metaclass__ = meta_func
使用 metaclass 的案例
- 动态修改类的方法和属性, 例如给方法增加
decorator
- 类的序列化和反序列化
- 在生成类的时候进行接口检查和接口注册
- 对第三方库进行
monkey patch
- 生成代理类
- 动态mixin
- 控制实例对象的生成, 例如单体实例, 监控所有生成的实例对象
搜索stackoverflow 能找到大量使用 metaclass 的设计模式.
使用 metaclass 的原则
metaclass 会降低代码的可读性, 并且很多使用 metaclass 的场景都有替代方案, 因此必须牢记下面的 忠告:
Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don’t (the people who actually need them know with certainty that they need them, and don’t need an explanation about why).
Tim Peters Python Guru