接着上一篇的讲。 现在我们知道了,metaclass 生 class,class 生 instance。 但是 metaclass 还可以有它的 metametaclass,metametaclass 还可以有... 如此反复,永无止境。这样想起来,脑袋就有点晕了。 其实在 python 中万物皆对象而已,所有对象皆有其类型,对象的类型也还是对象!而类型对象的类型就是它自己。 而前面说过的所谓 instance、class、metaclass 等东西,都只是不同种类的对象而已。 判断对象是什么对象的唯一方法就是通过其提供的“接口”,这就是所谓的 duck typing!只要一个对象实现了成为一个 class 所需的接口,它就是 class !metaclass 亦然。 那么我们不如先来讨论讨论 metaclass 的接口吧,看看究竟需要实现哪些接口能使一个对象成为一个 metaclass。 先来看一些等价关系:
class Temp(object): __metaclass__ = Meta a = 1 def __init__(self, a): self.a = a上面代码其实等价于:
Temp = Meta('Temp', (object,), {'a':1, '__module__':'current module name', '__metaclass__':the object Meta, '__init__':function object __init__})(class的语法原来只是个语法糖而已,汗!) 由此可见 Meta 首先应该是个 callable,并且应该接受如上所示的三个参数。
t = Temp(2) # 构建 Temp 的 instance从这一句我们可以看出 Temp 也应该是个 callable 对象。 而我们知道 Temp 对象其实是调用 Meta 所返回的,也就是说 Meta 这个 callable 对象返回的还应该是一个 callable 对象。 典型地,如果 Meta 是一个 class,意味着它应该实现一个 __call__ 方法。这样的话,那么上面那句就可以等价为:
t = Temp.__call__(2)上面说的这几点基本上可以作为判断一个对象能否成为 metaclass 的标准了:一个接受三个参数并返回另一个 callable 对象的 callable 对象! 不急,在继续分析之前我们不妨利用刚才发现的这一点搞点小怪先,呵呵。
def Meta(name, bases, attrs): def _class(a): return a return _class class Temp(object): ''' >>> Temp(1) 1 >>> Temp('hello') 'hello' ''' __metaclass__ = Meta继续分析,虽然可以像上面那样恶搞,不过要想写个有点实际用处的 metaclass ,还是通过 class 来实现比较方便。 最典型的方法便是直接继承 type 了,毕竟那是所有 new-style class 的 metaclass,在 python3000 里就要成为所有 class 默认的 metaclass 了。 可以说大部分 metaclass 的实现都是这么做的,不过下面要分析的这一例却是个例外,虽然不像上面我们写的那个 metaclass 那么奇怪,不过分析起来也不是那么容易的。 不过我们还需要继续澄清一些事实,先看这个例子:
class Temp(object): @staticmethod # 这一句可以忽略,不管有没有这句,__new__ 都是静态方法 def __new__(cls, a): return object.__new__(cls, a) def __init__(self, a): self.a = a def __getattribute__(self, name): return super(Temp, self).__getattribute__(name) def __getattr__(self, name): return super(Temp, self).__getattr__(name) t = Temp(2) print t.a在默认的 metaclass type 的实现中,上面这句,也就是 type 的 __call__ 方法,其实是分以下两步完成的:
t = Temp.__new__(Temp, 2) # 调用 staticmethod __new__,创建 instance t.__init__(2) # 调用该 instance 的构造函数,初始化 instance另外,既然 Temp 实现了 __getattribute__, t.a 实际上等价于:
try: t.__getattribute__(self, 'a') except AttributeError: t.__getattr__(self, 'a')到这里基本上一些概念问题已经搞清楚了,下一篇终于可以正式开始研究这里的代码了。 参考: Unifying types and classes in Python 2.2 这是老大对 python2.2 以后的“python对象模型”的深刻的描述 The Python 2.3 Mehod Resolution Order 这也是今天碰巧看到的好文,虽然与本文没有什么联系,不过,此文深入讲解了 python2.3 以后对多继承的实现, 我也是看完这篇才知道实现个多继承是如此的复杂,不过幸好他们找到了合适的算法。 另外对于平时不经常接触算法的人(比如我)来说,偶尔用数学的思维思考思考还有很有好处的。 New-style Classes 这里是 new-style class 相关的文献的集合。 另外想找这方面中文资料的兄弟可以去啄木鸟:python中的新型类及其实例详解 Metaclasses(元类)
3 评论:
代码没了缩进,看着着实累,是网站的问题吧?想办法改善一下,用全角空格?
另外什么叫语法糖?
看元类编程有点辛苦,而且我看完了还是不知道用在哪里合适。不知道你有没有使用上的体会?
改好了,在 blogger 上写代码着实不易,也算是缩进带来的麻烦之一了啊,呵呵。
语法糖 也没找到什么权威的定义,一般是指能被其他更基础的语法所替代的语法吧。
元类编程实际用到的地方好像确实不多,在实际代码中,我也就在 django、sqlobject 里面实现其申明式的 model 定义的语法时看到 metaclass 的身影。
一般用到 metaclass 的场景估计都是比较超越常规的场景。
不过理解了 metaclass 对于理解 python 整个类型系统、对象模型都是很有帮助的。
我现在越来越感觉到 python2.2 的 new-style class 是一个非常大的进步,而在 python3000 中更是丢掉了向后兼容,一切将会变得更加的一致和统一。
恩,现在就漂亮多了
发表评论