函数式编程,和面向对象编程一样,是现在很流行的一种编程范式。
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。由于Python允许变量的存在,所以Python不是纯函数式编程。
函数式编程最大的特点就是将函数看作是一等公民,也就是和其他数据类型、数据结构一样,函数也可以赋给一个变量,作为参数、传入其他函数,或者是作为其他函数的返回值。而将函数作为参数的函数我们称之为高阶函数。
高阶函数
>>> f = abs
>>> f(-10)
10
>>> abs(-10)
10
>>> abs = 10
>>> abs(-10)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
abs(-10)
TypeError: 'int' object is not callable
从上面的代码可以看出,函数实际上是一个功能,任何一个变量可以指向一个函数,获得这个功能;而函数名是什么呢?函数名也是一个变量,只是这个变量初始指向了这个函数,当然也可以将这个变量指向其他值(实际上当然不能这么写);同时,一个变量,当然也可以作为参数传入函数啊,所以函数也可以作为参数传入其他函数。
>>> def fun(x,y,p):
print(p(x,y))
>>> fun(2,3,pow)
8
这就是一个最简单的将函数作为参数传入参数的例子。在Python中有许多内置的高阶函数
map
map函数接收两个参数,一个func函数和一个Iterable对象。
func函数接收一个参数,将func函数作用于Iterable对象中的每一个元素,并返回一个map对象。
>>> def fun(x):
return x + 3
>>> map(fun, range(10))
<map object at 0x03234BD0>
>>> m = map(fun, range(10))
>>> isinstance(m,Iterator)
True
>>> list(m)
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
从中可以看出,由于map对象也是一个Iterator,是一个懒惰序列,可以用list函数列出所有值。使用map对象可以对Iterable对象的每一个值进行函数操作,可以代替平时需要使用循环完成的功能。
reduce
reduce函数接收两个参数:func函数和一个序列。其中的func函数接收两个参数,对序列中的值进行计算,并将结果与下一个值进行计算,直至产生最终结果
>>> from functools import reduce
>>> def add(x,y):
return x*10+y
>>> reduce(add,range(5))
1234
**map相当于对Iterable中元素逐一操作(str也能逐字符操作),reduce则能够将所有元素最终整合为一个结果。**map/reduce配合使用可以实现一些强大的功能
>>> def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
return reduce(fn, map(char2num, s))
>>> str2int('12306')
12306
filter
filter函数的作用是筛选某一序列中符合条件的序列,接收一个func函数和一个序列
>>> def is_palindrome(n):
return str(n)==str(n)[::-1]
>>> output = filter(is_palindrome,range(1000))
>>> list(output)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99]
filter函数的重点在于构造用于判别元素是否符合条件的func函数!filter功能很强大,譬如下面的代码实现了一个输出素数的generator:
>>> def _odd_iter():
n = 1
while True:
n = n + 2
yield n
>>> def _div_fun(n):
def _div_check_fun(x):
return x % n > 0
return _div_check_fun
>>> def primes():
yield 2
iter = _odd_iter()
while True:
n = next(iter)
yield n
iter = filter(_div_fun(n), iter)#这里用到了闭包
>>> p = primes()
>>> next(p)
2
>>> next(p)
3
>>> next(p)
5
生成了一个懒惰计算的generator,然后就可以一个一个生成素数了!
sorted
sorted函数是一个排序函数
>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
sorted经常会有许多其他排序需求,这些就可以写一个排序函数,写入sorted函数的关键字参数key中
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
>>> def fun(s):
return s[1].lower()
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=fun, reverse=True)
['Credit', 'bob', 'Zoo', 'about']
上面的例子,想要通过元素的第二个字母对list进行排序,那么传入的key参数函数中就应该返回第二个字母。
从上面的例子可以看出,高阶函数的抽象能力非常强大,能够使得代码保持简洁!
(By MrHammer 2016-05-21 下午5点 @Hohai Rainy)