Python中的函数式编程

虽然人们总把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中的条件调用进行短路处理

01  # Normal statement-based flow control
02  if <cond1>:   func1()
03  elif <cond2>: func2()
04  else:         func3()
05  
06  # Equivalent "short circuit" expression
07  (<cond1> and func1()) or (<cond2> and func2()) or (func3())
08  
09  # Example "short circuit" expression
10  >>> x = 3
11  >>> def pr(s): return s
12  >>> (x==1 and pr('one')) or (x==2 and pr('two')) or (pr('other'))
13  'other'
14  >>> x = 2
15  >>> (x==1 and pr('one')) or (x==2 and pr('two')) or (pr('other'))
16  'two'

我们的表达式版本的条件调用看上去可能不算什么,更象是个小把戏;然而,如果我们注意到lambda算子必须返回一个表达式,这就更值得关注了。既然如我们所示,表达式能够通过短路包含一个条件判断,那么,lambda表达式就是个完全通用的表达条件判断返回值的手段了。我们来一个例子:

Python中短路的Lambda
01  >>> pr = lambda s:s
02  >>> namenum = lambda x: (x==1 and pr("one")) \
03  ....                  or (x==2 and pr("two")) \
04  ....                  or (pr("other"))
05  >>> namenum(1)
06  'one'
07  >>> namenum(2)
08  'two'
09  >>> namenum(3)
10  'other'

将函数作为具有首要地位的对象

前面的例子已经表明了Python中函数具有首要地位,但有点委婉。当我们用lambda操作创建一个函数对象时, 我们所得到的东西是完全通用的。就其本质而言,我们可以将我们的对象同名字"pr"和"namenum"绑定到一起, 以完全相同的方式,我们也也完全可以将数字23或者字符串"spam" 同这些名字绑定到一起。但是,就象我们可以无需将其绑定到任何名字之上就能直接使用数字23(也就是说,它可以用作函数的参数)一样,我们也可以直接使用我们使用lambda创建的函数对象,而无需将其绑定到任何名字之上。在Python中,函数就是另外一种我们能够就像某种处理的值。

我们对具有首要地位的对象做的比较多的事情就是,将它们作为参数传递给函数式编程固有的函数map()、reduce()和filter()。这三个函数接受的第一个参数都是一个函数对象。

map()针对指定给它的一个或多个列表中每一项对应的内容,执行一次作为参数传递给它的那个函数 ,最后返回一个结果列表。

reduce()针对每个后继项以及最后结果的累积结果,执行一次作为参数传递给它的那个函数;例如,reduce(lambda n,m:n*m, range(1,10))是求"10的阶乘"的意思(换言之,将每一项和前面所得的乘积进行相乘)

filter()使用那个作为参数传递给它的函数,对一个列表中的所有项进行”求值“,返回一个由所有能够通过那个函数测试的项组成的经过遴选后的列表。

我们经常也会把函数对象传递给我们自己定义的函数,不过一般情况下这些自定义的函数就是前文提及的内建函数的某种形式的组合。

通过组合使用这三种函数式编程内建的函数, 能够实现范围惊人的“执行流程”操作(全都不用语句,仅仅使用表达式实现)。
Python中的函数式循环

时间: 2024-10-26 21:00:23

Python中的函数式编程的相关文章

Fn.py:享受Python中的函数式编程

尽管Python事实上并不是一门纯函数式编程语言,但它本身是一门多范型语言,并给了你足够的自由利用函数式编程的 便利.函数式风格有着各种理论与实际上的好处(你可以在Python的文档中找到这个列表): 形式上可证 模块性 组合性 易于调试及测试 虽然这份列表已经描述得够清楚了,但我还是很喜欢Michael O.Church在他的文章"函数式程序极少腐坏(Functional programs rarely rot)"中对函数式编程的优点所作的描述.我在PyCon UA 2012期间的讲

Python Decorator 和函数式编程

来源:https://www.oschina.net/translate/decorators-and-functional-python Python Decorator 和函数式编程 英文原文:Decorators and Functional Python Decorators 是Python中最重要的特性之一. 它除了使Python更好用外的, 它还能帮助我们以一种更有趣的方法考虑问题--函数式编程的方法 我会尝试着从零开始解释Decorator是怎么工作的. 首先, 我们会介绍一些帮助

可爱的Python:Python中的TK编程

David Mertz 用源代码样本以及详细的说明介绍了 TK 和Tkinter 封装器(Python 的 GUI库).为了更便于操作,他演示了曾在以前很多文章中使用的 Txt2Html前端程序的 GUI移植示例.当然,他认为您会定期阅读其专栏. 我想要向您介绍能想像到的开始 GUI 编程的最简单方法,就是使用 Scriptics 的 TK 和 Tkinter 封装器.我们将与 developerWorks 中的 "Python 中的 curses 编程" 提到的 curses 库进行

Python中的并发编程实例_python

一.简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执行,这个控制流被称为该进程的主线程.在任何给定的时刻,一个程序只做一件事情. 一个程序可以通过Python库函数中的os或subprocess模块创建新进程(例如os.fork()或是subprocess.Popen()).然而,这些被称为子进程的进程却是独立运行的,它们有各自独立的系统状态以及

《Python核心编程(第3版)》——2.4 Python中的网络编程

2.4 Python中的网络编程 既然你知道了所有关于客户端/服务器架构.套接字和网络方面的基础知识,接下来就让我们试着将这些概念应用到Python中.本节中将使用的主要模块就是socket模块,在这个模块中可以找到socket()函数,该函数用于创建套接字对象.套接字也有自己的方法集,这些方法可以实现基于套接字的网络通信. 2.4.1 socket()模块函数 要创建套接字,必须使用socket.socket()函数,它一般的语法如下. socket(socket_family, socket

DotNetNuke中的函数式编程手法分析

"Dear, you love me, you just don't know you love me"是美国肥皂剧FRIENDS中的经典台词,中文翻译为<老友记>或者<六人行>,比较一下这句:"Programmer, you use FP, you just don't know you use FP",句式上和逻辑上是不是很相似? 现在我想说说FP,Functional Programming,中文翻译为函数式编程,与"命令编程

Python 进阶_函数式编程

目录 目录 函数式编程 Python 函数式编程的特点 高阶函数 匿名函数 lambda 函数式编程相关的内置函数 filter 序列对象过滤器 map reduce 折叠 自定义的排序函数 最后 函数式编程 首先要确定一点就是:函数 != 函数式,函数式编程是一种编程的范式. 特点: 把计算视为函数而非指令 纯函数式编程,不需要变量,没有副作用,测试简单 支持高阶函数,代码简洁 Python 函数式编程的特点 需要注意的是,Python 不是也不可能会成为一种纯函数是编程语言,但 Python

F#入门:使用.NET Framework中的函数式编程技术

本文讨论: 安装 F# F# 语言基础 .NET 互操作性 异步 F# 本文使用了以下技术: .NET Framework, F# 目录 为什么要使用 F#? 安装 F# 您好,F# Let 表达式 关键字 For 管道 F# 也能够处理对象 异步 F# 与 F# 合作 作 为 Microsoft .NET Framework 家族的新成员,F# 提供类型安全.性能以及类似脚本语言的工作能力,所有这些都是 .NET 环境的一部分.此函数式语言由 Microsoft 研究院的 Don Syme 发

简述Python中的面向对象编程的概念_python

面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行.为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度. 而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象