为了深入学习本章所述的知识,一定要阅读 Python 语言参考手册中“Data Model”一章里的“3.3.3. Customizing class creation”一节(https://docs.python.org/3/reference/datamodel.html#metaclasses)、“Built-in Functions”一章中 type 类的文档(https://docs.python.org/3/library/functions.html#type),以及标准库参考中“Built-in Types”一章里的“4.13. Special Attributes”一节(https://docs.python.org/3/library/stdtypes.html#special-attributes)。此外,在标准库参考中,types 模块的文档(https://docs.python.org/3/library/types.html)说明了 Python 3.3 引入的两个新函数,这两个函数用于辅助类元编程:types.new_class(...) 和 types. prepare_class(...)。
类装饰器的规范是“PEP 3129—Class Decorators”(https://www.python.org/dev/peps/pep-3129/),作者是 Collin Winter,参考实现由 Jack Diederich 提供。Jack Diederich 在 PyCon 2009 大会上做了一场题为“Class Decorators: Radically Simple”的演讲(视频:https://www.youtube.com/watch?v=cAGliEJV9_o),对这个功能做了简单介绍。
Alex Martelli 写的《Python 技术手册(第 2 版)》对元类的说明很出色,还实现了 metaMetaBunch 元类,其作用与示例 21-2 中简单的 record_factory 函数一样,不过完善得多。Martelli 没有探讨类装饰器,因为这个功能在那本书出版后才引入。Beazley 和 Jones 在他们合著的《Python Cookbook(第 3 版)中文版》中提供了几个示例,很好地演示了类装饰器和元类。Michael Foord 写了一篇引人入胜的文章,题为“Meta-classes Made Easy: Eliminating self with Metaclasses”(http://www.voidspace.org.uk/python/articles/metaclasses.shtml)。副标题(“借助元类去掉 self”)说明了一切。
元类的主要参考资料有引入特殊方法 __prepare__ 的“PEP 3115—Metaclasses in Python 3000”(https://www.python.org/dev/peps/pep-3115/),以及 Guido van Rossum 发布的文章“Unifying types and classes in Python 2.2”(https://www.python.org/download/releases/2.2.3/descrintro/)。这篇文章也适用于 Python 3,谈到了后来称为“新式类”的语义,包括描述符和元类,一定要阅读。Guido 在文中提到了 Ira R. Forman 与 Scott H. Danforth 合著的 Putting Metaclasses to Work: a New Dimension in Object-Oriented Programming(Addison- Wesley 出版社,1998 年),他在亚马逊上给这本书打了五颗星,还写了如下评论:
这本书促成 Python 2.2 实现了元类
可惜,这本书已经绝版了。Python 通过
super()函数实现了协作式多重继承,谈到这方面的难题时,我总会提到这本书;据我所知,这本书是这方面最好的教程。6
6摘自亚马逊网站中 Putting Metaclasses to Work 的商品目录页面(http://amzn.to/1HGwKDO)。目前还有二手书出售。我买了一本,发现很难读懂,不过以后我可能会再读。
“PEP 487—Simpler customization of class creation”(https://www.python.org/dev/peps/pep-0487/)提议为 Python 3.5(写到这里时,处于内测阶段)添加一个新的特殊方法 __init_subclass__,7 让普通的类(即,不是元类)定制子类的初始化。与类装饰器一样,__init_subclass__ 方法能让类元编程变得更简单,但会导致元类这个强大的功能更难正确使用。
7现在,Python 3.5 已经正式发布,PEP 487 没有在 Python 3.5 中实现,而是推迟到 Python 3.6 中。——编者注
如果你喜欢元编程,可能希望 Python 提供基本的元编程功能——Elixir 和 Lisp 语言族提供的句法宏。天遂人愿,我们有 MacroPy(https://github.com/lihaoyi/macropy)可用。
杂谈
这是本书最后一篇“杂谈”了,首先我要从 Brian Harvey 与 Matthew Wright 合写的著作中引述一大段文字。Harvey 和 Wright 是加州大学(伯克利分校和圣巴巴拉分校)的计算机科学教授,他们在合著的 Simply Scheme 一书中写道:
计算机科学的教学方式分成两个流派,可以描述如下。
(1) 保守派 计算机程序已经变得极其大而复杂,超过了人类思维所能承载的限度。因此,计算机科学教育的任务是训练平庸的程序员,这样 500 个人合作便能开发出恰好满足需求的程序。
(2)激进派 计算机程序已经变得极其大而复杂,超过了人类思维所能承载的限度。因此,计算机科学教育的任务是教人如何拓展思维,打破常规,学习以更广博、更强大和更灵活的方式思考,让思维超越程序。编程思想的各个方面在程序中必会得到充分体现。8[Brian Harvey and Matthew Wright, Simply Scheme (MIT Press, 1999), p. xvii. 伯克利分校的网站中有此书全文(https://www.eecs.berkeley.edu/~bh/ss-toc2.html)。]}
——Brian Harvey 和 Matthew Wright
Simply Scheme 前言这是 Harvey 和 Wright 对计算机科学教育的夸张描述,不过也适用于编程语言的设计。现在,你应该能猜到,我赞成“激进派”,我认为 Python 也是以这种态度设计的。
为了稳扎稳打,Java 从一开始使用的就是存取方法,而且众多 Java IDE 都提供了生成读值方法和设值方法的快捷键;与此相比,特性算是一大进步。特性的主要优点是,一开始编写程序时可以先把属性设为公开的(遵照 KISS 原则),因为公开的属性无需大幅改动,随时都能变成特性。不过,描述符更进一步,提供了去除存取方法中逻辑重复的机制。这种机制特别有效,因此基本的 Python 结构在背后也用到了描述符。
另一个强大的想法是,把函数当作一等对象,这为高阶函数铺平了道路。描述符和高阶函数合在一起实现,使得函数和方法的统一成为可能。函数的
__get__方法能即时生成方法对象,把实例绑定到self参数上。这种做法相当优雅。9最后,Python 中的类也是一等对象。作为一门对初学者友好的语言,Python 能提供类装饰器,允许用户定义功能完整的元类,这些强大的抽象真是太棒了。最棒的是,这些高级功能没有拖累日常编程(其实无形中提供了帮助)。Django 和 SQLAlchemy 等框架用起来这么方便,发展得这么成功,很大程度上归功于元类,而这些工具的用户甚至不知道元类的存在。不过,他们可以学习,去创建下一个伟大的库。
我还未见过有哪门语言像 Python 这样竭尽所能,让初学者易于入门,让专业人士用着顺手,让程序高手欢欣鼓舞。感谢 Guido van Rossum,以及为此努力的每个人。
9David Gelernter 写的 Machine Beauty(Basic Books 出版社)是一本非常有趣的小书,对工程作品(从桥梁到软件)的优雅和美学做了阐述。