Functional Programming in Python

什么是函数式编程?

Functional programming is what you do when you program in languages like

 

Lisp, Scheme, Clojure, Scala, Haskell, ML, OCAML, Erlang, or a few others.  

函数式编程的特点

函数是一等公民

例如你可以把一个函数作为参数传给另一个函数

任何对数据的操作都适用于函数

举个例子——装饰器的实现

递归被用作主要的结构控制

是没有循环的

对于某些语言而言

并不适用于 Python...

强大的列表处理能力

多级嵌套的列表与递归一起取缔了循环

在Python中:

  • Python对列表的操作很灵活,包括很多强大的内建方法、标准库以及第三方库。
  • 其本身并未做递归优化,所以总有许多循环的过程,是这些强大的列表操作无法替代的。
  • 在多数情况下,推荐使用列表推导来代替map和filter,因为效率上列表推导更胜一筹。(zip and reduce is good ^_^)

无副作用(放心食用)

在纯粹的函数式编程语言(例如Haskell)中,变量不可变:

你无法声明并赋值一个数据结构,

然后再在之后的程序流中改变它。

在Python中:

  1. 死心吧,这是不可能的。
  2. 不过你可以通过描述符来拒绝对象属性的变更。
  3. 当你想要改变时,返回一个新的深拷贝对象(通过函数获取新的数据结构)。

没有状态

使用表达式求值来代替“状态”。

在纯粹的函数式编程语言里,一个程序即是一个表达式。

在Python中:

  1. 可以实现,但是大多数情况下不推荐这么做。
  2. 取舍,一般取决于是否增加了可读性。

实体重于过程

这是个哲学问题...请参考后面的例子。

函数式编程语言更关注什么要被计算,

而不是它如何被计算。

高阶函数

Python支持将函数当成普通对象来处理,所以

你懂的...

简单而言,就是一种操作操作其他函数的函数的函数。

吐槽:这个函数式编程特性混入了奇怪的东西...

Examples

Good

原版

FP

安全的闭包

class Adder(object):
    def __init__(self, n):
        self.n = n
    def __call__(self, m):
        return self.n + m

add5_i = Adder(5)
def make_adder(n):
    def adder(m):
        return m+n
    return adder


add5_f = make_adder(5)
>>> add5_i(10)
15

>>> add5_f(10)
15

>>> add5_i.n = 10   # 状态改变
>>> add5_i(10)      # 结果随程序流而改变,不安全!
20

食用

FP版本也不是完全安全的吗?

# 一个坑
>>> adders = []
>>> for n in range(5):
        adders.append(lambda m: m+n)

>>> [adder(10) for adder in adders]
[14, 14, 14, 14, 14]


>>> n = 20
>>> [adder(10) for adder in adders]
[30, 30, 30, 30, 30]

# 什么鬼?
# --Python并不是纯粹的函数式编程语言,
# 变量的状态改变时有发生!

# 解决方案(默认参数)
>>> adders = []
>>> for n in range(5):
        adders.append(lambda m, n=n: m+n)

>>> [adder(10) for adder in adders]
[10, 11, 12, 13, 14]

# 其实完全安全是可以做到的
# 因为我们有 Plan B
>>> from operator import add
>>> from functools import partial
>>> adders = []
>>> for n in range(5):
        adders.append(partial(add, n))

# thanks to 严波老师
# 是他告诉我 partial 这么个好玩的东西
# 然而还是存在一个小隐患,你可以重载绑定的默认参数
>>> add4 = adders[4]
>>> add4(10, 100)
110

Bad

原版(Good)

FP(Bad)

def factorialR(N):
    "Recursive factorial function"
    assert isinstance(N, int) and N >= 1
    return 1 if N <= 1 else N * factorialR(N-1)
def factorialI(N):
    "Iterative factorial function"
    assert isinstance(N, int) and N >= 1 product = 1
    while N >= 1:
        product *= N
        N-=1
    return product

Best

from operator import mul
def factorialHOF(n):
    return reduce(mul, range(1, n+1), 1)

递归更好实现的算法

快速排序

worst

# 正常版本的qsort
def qsort(lst, cmp):
    if len(lst) <= 1:
        return lst
    pivot = lst[0]
    pivots = filter(lambda x: cmp(x, pivot) == 0, lst)
    small = qsort(filter(lambda x: cmp(x, pivot) < 0, lst), cmp)
    large = qsort(filter(lambda x: cmp(x, pivot) > 0, lst), cmp)
    return small + pivots +large
# 精神病患者的qsort
def qsort2(lst, cmp):
    def filter_cmp(f, x): return f(cmp(x, lst[0]), 0)
    return lst if len(lst) <= 1 else sum(map(lambda op: filter(partial(filter_cmp, op), lst) \
        if op is eq else qsort2(filter(partial(filter_cmp, op), lst), cmp), [lt, eq, gt]), [])

Sum up

语言是实现思想的工具,

所以 范式 和 库、设计模式 之流的功能相似,

只是为了让我们更方便地实现罢了。

Thanks for Whatching

Bonus

  • operator
  • functools

  • itertools
     

  • pyrsistent

  • toolz

  • hypothesis

  • more_itertools

Functional Programming in Python

By magine

Functional Programming in Python

2015年8月13日,豆瓣北郡分享会。

  • 451