为什么Python不适合函数式编程?
我一直认为在Python中可以进行函数式编程。因此,当我看到在这个问题中,Python并没有得到太多提及时,我感到很惊讶。而且当提到Python时,通常评价也不太好。不过,关于这个问题并没有给出太多理由(提到的有缺少模式匹配和代数数据类型)。所以我想问的是:为什么Python在函数式编程方面表现得不太好?除了缺少模式匹配和代数数据类型,还有其他原因吗?或者说这些概念对函数式编程来说真的那么重要,以至于不支持它们的语言只能被归类为二流的函数式编程语言?(请注意,我对函数式编程的经验相当有限。)
9 个回答
Scheme 语言没有代数数据类型或者模式匹配,但它绝对是一种函数式编程语言。从函数式编程的角度来看,Python 有一些让人烦恼的地方:
受限的 Lambda 表达式。因为 Lambda 只能包含一个表达式,而在表达式的上下文中你不能轻松做所有事情,这意味着你能“即时”定义的函数是有限的。
条件语句是语句,而不是表达式。这意味着,比如说,你不能在 Lambda 里面放一个条件语句。(在 Python 2.5 中用三元运算符解决了这个问题,但看起来不太好。)
Guido 有时会威胁要删除 map、filter 和 reduce这些功能。
另一方面,Python 也有词法闭包、Lambda 表达式和列表推导(这些其实是“函数式”的概念,不管 Guido 是否承认)。我在 Python 中做了很多“函数式风格”的编程,但我并不觉得它是最理想的选择。
Guido在这里有个很好的解释:链接。以下是最相关的部分:
我从来没有认为Python受到函数式语言的强烈影响,不管别人怎么说或者怎么想。我对命令式语言,比如C和Algol 68更熟悉,虽然我让函数成为了一等公民,但我并不把Python看作是一种函数式编程语言。不过,早些时候,很明显用户希望能用列表和函数做更多的事情。
...
值得注意的是,虽然我没有把Python设想成一种函数式语言,但闭包的引入在许多其他高级编程特性的发展中是很有用的。例如,新式类、装饰器和其他现代特性的一些方面都依赖于这个能力。
最后,尽管这些年来引入了许多函数式编程的特性,Python仍然缺少一些“真正的”函数式编程语言中的特性。例如,Python不进行某些类型的优化(比如尾递归)。一般来说,由于Python极其动态的特性,它无法进行像Haskell或ML那样的编译时优化。这也没关系。
我从中提炼出两点:
- 这门语言的创造者并不真正认为Python是一种函数式语言。因此,你可能会看到一些“像函数式”的特性,但不太可能看到什么是绝对的函数式特性。
- Python的动态特性限制了你在其他函数式语言中看到的一些优化。确实,Lisp和Python一样动态(甚至更动态),所以这只是部分解释。
你提到的问题是关于哪些编程语言同时支持面向对象编程和函数式编程。虽然Python在函数式编程方面表现得还不错,但它并不鼓励使用函数式编程。
反对在Python中使用函数式编程的一个主要理由是,Python的创始人Guido在设计语言时,仔细考虑了命令式和面向对象的用例,而对函数式编程的用例则没有那么重视。当我用命令式风格写Python代码时,它是我见过的最优美的语言之一。但当我用函数式风格写Python时,它就变得像那些没有终身仁慈独裁者的普通语言一样丑陋和不愉快。
这并不是说Python的函数式编程就不好,只是说如果你换成一个更支持函数式编程的语言,或者写面向对象的Python代码,你会轻松很多。
在Python中,我觉得缺少的一些函数式特性有:
- 没有模式匹配和尾递归意味着你的基本算法必须用命令式方式来写。Python中的递归既丑陋又慢。
- 小型的列表库和缺少函数式字典意味着你必须自己写很多东西。
- 没有柯里化或组合的语法意味着无点风格的代码和显式传递参数的代码一样,都是满满的标点符号。
- 使用迭代器而不是惰性列表意味着你必须知道自己想要效率还是持久性,如果想要持久性,就得到处调用
list
。 (迭代器只能使用一次) - Python简单的命令式语法,加上它简单的LL1解析器,意味着更好的if表达式和lambda表达式的语法几乎是不可能的。Guido喜欢这样,我认为他是对的。