metaclass in python (part 1)

阅读更多
python 的东西虽然概念上 容易理解 ,但是实际用起来却也不都是那么容易的。这个 metaclass 就是典型一例。虽然早知道了它是什么,不过要说出它具体能干点啥,一时半会还真想不起来。
先看看官方文档中的定义吧:
__metaclass__
This variable can be any callable accepting arguments for name, bases, and dict. Upon class creation, the callable is used instead of the built-in type(). New in version 2.2.

The appropriate metaclass is determined by the following precedence rules:

  • If dict['__metaclass__'] exists, it is used.
  • Otherwise, if there is at least one base class, its metaclass is used (this looks for a __class__ attribute first and if not found, uses its type).
  • Otherwise, if a global variable named __metaclass__ exists, it is used.
  • Otherwise, the old-style, classic metaclass (types.ClassType) is used.

The potential uses for metaclasses are boundless. Some ideas that have been explored including logging, interface checking, automatic delegation, automatic property creation, proxies, frameworks, and automatic resource locking/synchronization.

看完这个似乎又能理清了一点东西:所谓 new-style class 和 old-style class 最根本的区别其实正在于它们的 metaclass 一个是 type,一个是 types.ClassType,所以只要一个 class 继承自 object 而又没有指定自己的 __metaclass__ 的话,其 metaclass 就会自动使用基类 object 的 __metaclass__,但是 object 却没有 __metaclass__,那就使用 type(object),也就是 type 了!

然后再 google 一下(这次是要 google code 一下了),看看实际生活中的代码都用它来干了点啥。不搜不知道,这一搜还真发现不少有意思的结果:
  1. 第一条[地址],是twisted里的代码
    __metaclass__ = type
    真有创意!根据上面定义中 __metaclass__ 查找顺序,在使用 old-style class 的 metaclass (也就是types.ClassType)之前会找一下全局变量 __metaclass__ ,而上面代码中通过定义模块全局变量 __metaclass__ ,使得模块中原来的 old-style class 立刻变成了 new-style class。使用这种方法来将 old-style class 升级为 new-style class,确实省了不少代码,毕竟将来的 python 中将会只存在 new-style class ,那时候便可放心地将这一句去掉了。聪明!(不过这样会导致查找 metaclass 的过程要多了几个步骤,效率上可能就 ... )
  2. 第二条[地址],从这个例子的路径看它是在 python25/tools/ 下面,不过翻了一下自己python25 安装目录下却没有发现这些代码,郁闷!
    在这个例子中,__metaclass__ 被当成了一种快捷定义 class 方法的方式了。
    我们知道在 class 中定义的方法其实默认都是 instance 方法,要使它们成为 class 方法需要使用 classmethod 进行装饰,对于有大量 class 方法的类来说,这的确是有点小麻烦。
    既然 class 中定义的方法是 class 的 instance 方法,那么在 type 中定义的方法岂不就是 type 的 instance 方法,也就正好是 class 方法了?
    这个例子便是利用这一点,通过继承 type,添加 type 的 instance 方法,也就是添加了 class 方法了。好聪明啊,呵呵 ;-)
  3. 第三条的用法与第一条类似,第四条[地址]来自传说中的 psyco !一看到这个名字差点没有勇气继续看下去了,不过还好,这个 metaclass 其实并不复杂,它的作用就是在 class 创建之后自动将它或 __psyco_bind__ 中指定的属性 bind 到 psyco,具体 bind 干了什么事情就只有对 psyco 有研究的兄弟来解答了,不过估计这样就可以进行某种特别的优化了。也许你要说了:这个工作也可以在 class 的 __init__ 或是 __new__ 方法里做啊。但是放在 __init__ 里面做的话你就需要其他的 class 都来继承你这个基类了,而使用 __new__ 的问题是它可以被子类 override 掉。
    使用 metaclass 的另一个好处是,你可以神不知鬼不觉地修改 class 的创建过程,比如
    这个例子里面,在模块中定义好 __metaclass__ 全局变量,那当其他的代码 from module import * 的时候,该 __metaclass__ 的定义就会自动作用于其后所定义的所有 class 了。
  4. 第五条和第八条的用法也和第一条类似,第六条貌似只是在使用 __metaclass__ 的情况下对 pickle 进行测试,没有什么特别的。至于第七条。。。。
而至于 第七(来自zope)和 第九(来自sqlobject)两条,还是听 下回分解吧。

不好意思,真的不是我卖关子,实在是被 第七条整晕了 = =",真不知道写这些代码的人是怎么想的,呵呵。
希望大家能从这些代码中看到 metaclass 的强大,动态语言的灵活。什么?还没看到?去看看 这个去!

你可能感兴趣的:(Python,Django,Google,生活,工作)