浅说Python 中的函数式编程

函数式编程

函数式编程思想有着50多年的历史,最古老的算是Lisp语言了。如今众多语言都在一定程度上支持函数式编程,如Python、Ruby、Javascript,而其他一些语言如Java、PHP都增加了对于匿名函数的支持,可以看到函数编程的思想还很受欢迎。
下面一段话引自知乎,原文地址

函数式编程是一种编程范式,常见的编程范式有命令式编程,函数式编程,逻辑式编程,值得一提的是面向对象编程也是一种命令式编程。命令式编程是面向计算机硬件的抽象,有变量(对应着存储单元),赋值语句(获取及存储指令),表达式(内存引用和算术运算)和控制语句(跳转指令),总之,命令式程序就是一个冯诺依曼机的指令序列。而函数式编程是面向数学的抽象,将计算描述为一种表达式求值,一句话,函数式程序就是一个表达式。
函数式编程中的函数并不是指计算机中的函数,而是指数学中的函数,即自变量的映射,即一个函数的值仅决定于函数参数的值,不依赖其他状态。在函数式语言中,函数作为一等公民,可以在任何地方定义,可以作为函数的参数和返回值,可以对函数进行组合。纯函数式编程语言中的变量也不是命令式编程中的变量,即存储状态的单元,而是代数中的变量,即一个值的名称。变量的值是不可变的,即不允许像命令式编程语言中的那样多次给一个变量赋值。严格意义上的函数式编程意味着不使用可变的变量,赋值,循环和其他命令式控制结构进行编程。

函数式编程的好处
引用透明、没有副作用,用知乎上答主的说法就是

一个好处是,函数既不依赖外部的状态也不修改外部的状态,这使得单元测试和调试更加容易。另一个好处是由于多个线程间不共享状态,因而可以避免发生死锁,可以很好地实现并发。
除此以外,函数式语言还具有以下特性:

  • 高阶函数(Higher-order function)
  • 偏应用函数(Partially Applied Functions)
  • 柯里化(Currying)
  • 闭包(Closure)

Python 中的函数式编程

Python中对函数式编程语言的支持主要集中在提供了map(),reduce(),filter()三个函数和lambda算子,让人吃惊的是仅凭这几个函数就几乎可以实现任意的Python程序。
关于这几个函数的使用,参见我的另外一篇博客,上面有对这几个函数的介绍。

下面的内容参考自这个网址
替换条件控制语句
对于下面的条件控制语句

1
2
3
4
5
6
if condition1:
func1()
elif contidion2:
func2()
else:
func3()

的结构,替换成下面的表达式

1
(condition1 and func1()) or (condition2 and func2()) or (func3())

下面是一个例子

1
2
3
4
5
6
7
8
9
>>> pr=lambda p:p
>>> print_number=lambda x:(x==1 and pr("it's one")) or (x==2 and pr("it's two")) or (pr("it's something else"))
>>> print_number(1)
"it's one"
>>> print_number(2)
"it's two"
>>> print_number(3)
"it's something else"
>>>

可以看到采用这种方式可以实现条件控制的替换。

替换循环控制语句

  • 替换for循环
    由于和map函数使用相同,所以可以直接用map函数来实现for循环,看下面的例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    >>> cubic=lambda x: x**3
    >>>
    >>>
    >>> for x in range(5):
    ... cubic(x)
    ...
    0
    1
    8
    27
    64
    >>> map(cubic,range(5))
    [0, 1, 8, 27, 64]
    >>>
  • 替换while循环
    相较而言,替换while循环稍稍麻烦一些,看下面的例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # statement-based while loop
    while <condition>:
    <pre-suite>
    if <break_condition>:
    break
    else:
    <suite>

    # Equivalent FP-style recursive while loop
    def while_block():
    <pre-suite>
    if <break_condition>:
    return 1
    else:
    <suite>
    return 0

    while_FP = lambda: <condition> and (while_block() or while_FP())
    while_FP()

函数式while_FP循环采用了递归的概念。当为true时,进入循环体,执行while_block();若为true时,返回1,while_FP()调用结束;若为false时,返回0,会继续执行or右侧的while_FP(),从而实现递归调用;若始终为false,则会持续递归调用while_FP(),这就实现了while语句中同样的功能。

看一个例子,下面的代码实现输入回显的echo功能,对比一下命令式编程和函数式编程。

1
2
3
4
5
6
7
8
9
#命令式编程版本
def echo_IMP():
while 1:
x = raw_input("IMP -- ")
print x
if x == 'quit':
break

echo_IMP()

下面是函数式编程版本

1
2
3
4
5
6
def monadic_print(x):
print x
return x

echo_FP = lambda: monadic_print(raw_input("FP -- "))=='quit' or echo_FP()
echo_FP()

再来看个例子,该例子实现找出笛卡尔积元组集合中元素之积大于25的所有元组。

1
2
3
4
5
6
7
bigmuls = lambda xs,ys: filter(lambda (x,y):x*y > 25, combine(xs,ys))
combine = lambda xs,ys: map(None, xs*len(ys), dupelms(ys,len(xs)))
dupelms = lambda lst,n: reduce(lambda s,t:s+t, map(lambda l,n=n: [l]*n, lst))

print bigmuls([1,2,3,4],[10,15,3,22])

[(3, 10), (4, 10), (2, 15), (3, 15), (4, 15), (2, 22), (3, 22), (4, 22)]

文章目录
  1. 1. 函数式编程
  2. 2. Python 中的函数式编程
,