返回介绍

5.12 延伸阅读

发布于 2024-02-05 21:59:47 字数 5108 浏览 0 评论 0 收藏 0

接下来的两章继续探讨使用函数对象编程。第 6 章说明一等函数如何简化某些经典的面向对象设计模式,第 7 章说明函数装饰器(一种特别的高阶函数)和支持装饰器的闭包机制。

《Python Cookbook(第 3 版)中文版》(David Beazley 和 Brian K. Jones 著)的第 7 章是对本章和第 7 章很好的补充,那一章基本上使用不同的方式探讨了相同的概念。

Python 语言参考手册中的“3.2. The standard type hierarchy”一节对 7 种可调用类型和其他所有内置类型做了介绍。

本章讨论的 Python 3 专有特性有各自的 PEP:“PEP 3102—Keyword-Only Arguments”和“PEP 3107—Function Annotations”。

若想进一步了解目前对注解的使用,Stack Overflow 网站中有两个问答值得一读:一个是“What are good uses for Python3's‘Function Annotations’”,Raymond Hettinger 给出了务实的回答和深入的见解;另一个是“What good are Python function annotations?”,某 个回答中大量引用了 Guido van Rossum 的观点。

如果你想使用 inspect 模块,“PEP 362—Function Signature Object”值得一读,可以帮助了解实现细节。

A. M. Kuchling 的文章“Python Functional Programming HOWTO”对 Python 函数式编程做了很好的介绍。不过,那篇文章的重点是使用迭代器和生成器,这是第 14 章的话题。

fn.py(https://github.com/kachayev/fn.py) 是为 Python 2 和 Python 3 提供函数式编程支持的包。据作者 Alexey Kachayev 介绍,fn.py 提供了 Python“所缺少的函数式特性”。这个包提供的 @recur.tco 装饰器为 Python 中的无限递归实现了尾调用优化。此外,fn.py 还提供了很多其他函数、数据结构和诀窍。

Stack Overflow 网站中的问题“Python: Why is functools.partial necessary?”有个详实(而有趣)的回答,答主是 Alex Martelli,他是经典的《Python 技术手册》一书的作者。

Jim Fulton 开发的 Bobo 或许是第一个称得上是面向对象的 Web 框架。如果你对这个框架感兴趣,想进一步学习它最近的重写版本,先从“Introduction”入手。在 Joel Spolsky 的博客中,Phillip J. Eby 在评论中提到了 Bobo 的一些早期历史

杂谈

关于Bobo

我的 Python 编程生涯从 Bobo 开始。1998 年,我在自己的第一个 Python Web 项目中使用了 Bobo。当时我在寻找编写 Web 应用的面向对象方式,尝试过一些 Perl 和 Java框架之后,我发现了 Bobo。

1997 年,Bobo 开创了对象发布概念:直接把 URL 映射到对象层次结构上,无需配置路由。看到这种做法的精妙之处后,我被 Bobo 吸引住了。Bobo 还能通过分析处理请求的方法或函数的签名来自动处理 HTTP 查询。

Bobo 由 Jim Fulton 创建,他被人称为“Zope 教皇”(The Zope Pope),因为他在 Zope 框架的开发中的起到领衔作用。Zope 是 Plone CMS、SchoolTool、ERP5 和其他大型 Python 项目的基础。Jim 还是 ZODB(Zope Object Database)的创建者,这是一个事务型对象数据库,提供了 ACID(“atomicity, consistency, isolation, and durability”,原子性、一致性、隔离性和耐久性),它的设计目的是简化 Python 的使用。

后来,为了支持 WSGI 和现代的 Python 版本(包括 Python 3),Jim 从头重写了 Bobo。写作本书时,Bobo 使用 six 库做函数内省,这是为了兼容 Python 2 和 Python 3,因为这两个版本在函数对象和相关的 API 上做了修改。

Python 是函数式语言吗

2000 年左右,我在美国做培训,Guido van Rossum 到访了教室(他不是讲师)。在课后的问答环节,有人问他 Python 的哪些特性是从其他语言借鉴而来的。他答道:“Python 中一切好的特性都是从其他语言中借鉴来的。”

布朗大学的计算机科学教授 Shriram Krishnamurthi 在其论文“Teaching Programming Languages in a Post-Linnaean Age”的开头这样写道:

编程语言“范式”已近末日,它们是旧时代的遗留物,令人厌烦。既然现代语言的设计者对范式不屑一顾,那么我们的课程为什么要像奴隶一样对其言听计从?

在那篇论文中,下面这一段点名提到了 Python:

对 Python、Ruby 或 Perl 这些语言还要了解什么呢?它们的设计者没有耐心去精确实现林奈层次结构;设计者按照自己的意愿从别处借鉴特性,创建出完全无视过往概念的大杂烩。

Krishnamurthi 指出,不要试图把语言归为某一类;相反,把它们视作特性的聚合更有用。

为 Python 提供一等函数打开了函数式编程的大门,不过这并不是 Guido 的目的。他在“Origins of Python's Functional Features”一文中说,map、filter 和 reduce 的最初目的是为 Python 增加 lambda 表达式。这些特性都由 Amrit Prem 贡献,添加在 1994 年发布的 Python 1.0 中(参见 CPython 源码中的 Misc/HISTORY 文件)。

lambda、map、filter 和 reduce 首次出现在 Lisp 中,这是最早的一门函数式语言。然而,Lisp 没有限制在 lambda 表达式中能做什么,因为 Lisp 中的一切都是表达式。 Python 使用的是面向语句的句法,表达式中不能包含语句,而很多语言结构都是语句,例如 try/catch,我编写 lambda 表达式时最想念这个语句。Python 为了提高句法的可读性,必须付出这样的代价。6Lisp 有很多优点,可读性一定不是其中之一。

讽刺的是,从另一门函数式语言(Haskell)中借用列表推导之后,Python 对 map、filter,以及 lambda 表达式的需求极大地减少了。

除了匿名函数句法上的限制之外,影响函数式编程惯用法在 Python 中广泛使用的最大障碍是缺少尾递归消除(tail-recursion elimination),这是一项优化措施,在函数的定义体“末尾”递归调用,从而提高计算函数的内存使用效率。Guido 在另一篇博客文章(“Tail Recursion Elimination”)中解释了为什么这种优化措施不适合 Python。这篇文章详细讨论了技术论证,不过前三个也是最重要的原因与易用性有关。Python 作为一门易于使用、学习和教授的语言并非偶然,有 Guido 在为我们把关。

综上,从设计上看,不管函数式语言的定义如何,Python 都不是一门函数式语言。Python 只是从函数式语言中借鉴了一些好的想法。

匿名函数的问题

除了 Python 独有的句法上的局限,在任何一门语言中,匿名函数都有一个严重的缺点:没有名称。

我是半开玩笑的。函数有名称,栈跟踪更易于阅读。匿名函数是一种便利的简洁方式,人们乐于使用它们,但是有时会忘乎所以,尤其是在鼓励深层嵌套匿名函数的语言和环境中,如 JavaScript 和 Node.js。匿名函数嵌套的层级太深,不利于调试和处理错误。Python 中的异步编程结构更好,或许就是因为 lambda 表达式有局限。我保证,后面会进一步讨论异步编程,但是必须等到第 18 章。顺便说一下,promise 对象、期物(future)和 deferred 对象是现代异步 API 中使用的概念。把它们与协程结合起来,能避免掉入“回调地狱”。18.5 节会说明如何不用回调来做异步编程。

6此外,还有一个问题:把代码粘贴到 Web 论坛时,缩进会丢失。当然,这是题外话。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文