关于Python2.x中metaclass这一黑科技,我原以为我是懂的,只有当被打脸的时候,我才认识到自己too young too simple sometimes native。
为什么之前我认为自己懂了呢,因为我阅读过stackoverflow上的《what-is-a-metaclass-in-python》这一神作(注意,本文中专指e-satis的回答),在伯乐在线上也有不错的翻译《深刻理解Python中的元类(metaclass)》。而且在实际项目中也使用过metaclass,比如creating-a-singleton-in-python一文中提到的用metaclass创建单例,比如用metaclass实现mixin效果,当然,正是后面这个使用案列让我重新认识metaclass。
本文地址:
要点回顾不得不承认《what-is-a-metaclass-in-python》真的是非常棒,仔细阅读完这篇文章,基本上就搞清了metaclass。因此在这里,只是强调一些要点,强烈建议还没阅读过原文的pythoner去阅读一下。
第一:everything is objectpython中,一切都是对象,比如一个数字、一个字符串、一个函数。对象是类(class)的是实例,类(class)也是对象,是type的实例。type对象本身又是type类的实例(鸡生蛋还是蛋生鸡?),因此我们称type为metaclass(中文元类)。在《python源码剖析》中,有清晰的表示
在python中,可以通过对象的__class__属性来查看对应的类,也可以通过isinstance来判断一个对象是不是某一个类的实例。for example:
>>> class OBJ(object):
... a = 1
...
>>> o = OBJ()
>>> o.__class__
<class '__main__.OBJ'>
>>> isinstance(o, OBJ)
True
>>> OBJ.__class__
<type 'type'>
>>> isinstance(OBJ, type)
True
>>> type.__class__
<type 'type'>
>>>
第二:metaclass可以定制类的创建
我们都是通过class OBJ(obejct):pass的方式来创建一个类,上面有提到,类(class)是type类型的实例,按照我们常见的创建类的实例(instance)的方法,那么类(class)应该就是用(*args)的方式创建的。确实如此,python document中有明确描述:
class type(name, bases, dict)
With three arguments, return a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the __name__ attribute; the bases tuple itemizes the base classes and becomes the __bases__ attribute; and the dict dictionary is the namespace containing definitions for class body and becomes the __dict__ attribute. For example, the following two statements create identical type objects:
该函数返回的就是一个class,三个参数分别是类名、基类列表、类的属性。比如在上面提到的OBJ类,完全等价于:OBJ = type('OBJ', (), {'a': 1})
当然,用上面的方式创建一个类(class)看起来很傻,不过其好处在于可以动态的创建一个类。
python将定制类开放给了开发者,type也是一个类型,那么自然可以被继承,type的子类替代了Python默认的创建类(class)的行为,什么时候需要做呢
Some ideas that have been explored including logging, interface checking, automatic delegation, automatic property creation, proxies, frameworks, and automatic resource locking/synchronization.
那么当我们用class OBJ(obejct):pass的形式声明一个类的时候,怎么指定OBJ的创建行为呢,那就是在类中使用__metaclass__。最简单的例子:
1 class Metaclass(type): 2 def __new__(cls, name, bases, dct): 3 print 'HAHAHA' 4 dct['a'] = 1 5 return type.__new__(cls, name, bases, dct) 6 7 print 'before Create OBJ' 8 class OBJ(object): 9 __metaclass__ = Metaclass 10 print 'after Create OBJ' 11 12 if __name__ == '__main__': 13 print OBJ.a