可爱的 Python : Python中函数式编程,第一部分

英文原文:Charming Python: Functional programming in Python, Part 1,翻译:开源中国

摘要:虽然人们总把Python当作过程化的,面向对象的语言,但是他实际上包含了函数化编程中,你需要的任何东西。这篇文章主要讨论函数化编程的一般概念,并说明用Python来函数化编程的技术。

我们最好从艰难的问题开始出发:“到底什么是函数化编程呢?”其中一个答案可能是这样的,函数化编程就是你在使用Lisp这样的语言时所做的(还有Scheme,Haskell,ML,OCAML,Mercury,Erlang和其他一些语言)。这是一个保险的回答,但是它解释得并不清晰。不幸的是对于什么是函数化编程,很难能有一个协调一致的定义,即使是从函数化变成本身出发,也很难说明。这点倒很像盲人摸象。不过,把它拿来和命令式编程(imperative programming)做比较也不错(命令式编程就像你在用C,Pascal,C++,Java,Perl,Awk,TCL和很多其他类似语言时所做的,至少大部分一样 )。

让我们回想一下功能模块的绑定类。使用该类的特性,我们可以确认在一个给定的范围块内,一个特定的名字仅仅代表了一个唯一的事物。

 我个人粗略总结了一下,认为函数式编程至少应该具有下列几点中的多个特点。在谓之为函数式的语言中,要做到这些就比较容易,但要做到其它一些事情不是很难就是完全不可能:

  • 函数具有首要地位 (对象)。也就是说,能对“数据”做什么事,就要能对函数本身做到那些事(比如将函数作为参数传递给另外一个函数)。
  • 将递归作为主要的控制结构。在有些函数式语言中,都不存在其它的“循环”结构。
  • 列表处理作为一个重点(例如,Lisp语言的名字)。列表往往是通过对子列表进行递归取代了循环。
  • “纯”函数式语言会完全避免副作用。这么做就完全弃绝了命令式语言中几乎无处不在的这种做法:将第一个值赋给一个变量之后为了跟踪程序的运行状态,接着又将另外一个值赋给同一个变量。
  • 函数式编程不是不鼓励就是完全禁止使用语句,而是通过对表达式(换句话说,就是函数加上参数)求值(evaluation of expressions)完成任务. 在最纯粹的情形下,一个程序就是一个表达式(再加上辅助性的定义)
  • 函数式编程中最关心的是要对什么进行计算,而不是要怎么来进行计算。
  • 在很多函数式编程语言中都会用到“高阶”(higher order)函数 (换句话说,高阶函数就是对对函数进行运算的函数进行运算的函数)。

函数式编程的倡导者们认为,所有这些特性都有助于更快地编写出更多更简洁并且更不容易出Bug的代码。而且,计算机科学、逻辑学和数学这三个领域中的高级理论家发现,函数式编程语言和程序的形式化特性在证明起来比命令式编程语言和程序要简单很多。

Python内在的函数式功能

自Python 1.0起,Python就已具有了以上所列中的绝大多数特点。但是就象Python所具有的大多数特性一样,这些特点出现在了一种混合了各种特性的语言 中。 和Python的OOP(面向对象编程) 特性非常象,你想用多少就用多少,剩下的都可以不管(直到你随后需要用到它们为止)。在Python 2.0中,加入了列表解析list comprehensions)这个非常好用的”语法糖“。 尽管列表解析没有添加什么新功能,但它让很多旧功能看起来好了不少

Python中函数式编程的基本要素包括functionsmap()、reduce()、filter()和lambda算子(operator)。 在Python 1.x中,apply()函数也可以非常方便地拿来将一个函数的列表返回值直接用于另外一个函数。Python 2.0为此提供了一个改进后的语法。可能有点让人惊奇,使用如此之少的函数(以及基本的算子)几乎就足以写出任何Python程序了;更加特别的是,几乎 用不着什么执行流程控制语句。

所有(if,elif,else,assert,try,except,finally,for,break,continue,while,def)这 些都都能通过仅仅使用函数式编程中的函数和算子就能以函数式编程的风格处理好。尽管真正地在程序中完全排除使用所有流程控制命令可能只在想参 加”Python混乱编程“大赛(可将Python代码写得跟Lisp代码非常象)时才有意义,但这对理解函数式编程如何通过函数和递归表达流程控制很有 价值。

剔除流程控制语句

剔除练习首先要考虑的第一件事是,实际上,Python会对布尔表达式求值进行“短路”处理。这就为我们提供了一个if/elif/else分支语句的表达式版(假设每个分支只调用一个函数,不是这种情况时也很容易组织成重新安排成这种情况)。 这里给出怎么做:

对Python中的条件调用进行短路处理

我们的表达式版本的条件调用看