前言:函数式编程

函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,
就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程
的程序设计的基本单元。而函数式编程(请注意多了一个“式”字)——Functional Programming,
虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。

函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任
一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序
设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。

Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

1 lambda

python 允许使用lambda关键字来创建匿名函数,匿名函数可以很大程度上简化了函数的定义过程。
基本语法:使用冒号(:)分割函数的参数及返回值,
冒号左边放置函数的参数,如果多个参数,使用逗号(,)分割即可。
冒号(:)右边是函数的返回值
执行完lambda语句后实际上返回一个函数对象,如果对他进行调用,只需要给他绑定一个临时名字即可。

add=lambda x,y:x+y
print(add(1,5))
输出:6

2 filter()

filter()函数是一个过滤器,它的作用是在海量的数据中提取有用信息。
基本语法:filter()函数有两个参数:第一个参数可以是一个参数也可以是None,
如果是一个函数的话,则将第二个可迭代对象里的每一个元素作为函数的参数进行计算的,把返回True的值筛选出来;
如果第一个参数为None,则直接将第二个参数中为True的值帅选出来。

temp=filter(None,[1,0,False,True])
print(list(temp))
输出:[1, True]

def is_odd(n):
return n % 2==1
odds=filter(is_odd, range(1, 20))
L = list(odds)
print(L)

输出:[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

结合前面学的lambda进行精简代码
print(list(filter(lambda x:x%2,range(20))))
输出:[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

3 map()

Python内建了map()和reduce()函数。
我们先看map。map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
举例说明,比如我们有一个函数f(x)=x^2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下

map()传入的第一个参数是f,即函数对象本身。由于结果r是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。

def f(x):
return x * x
r = list(map(f, [1, 2, 3, 4, 5, 6]))
print(r)

然后是reduce()函数。
reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

计算流像是这个样子
f(x1, x2)
f(f(x1, x2), x3)
f(f(f(x1, x2), x3), x4)

比方说对一个序列求和,就可以用reduce实现:

from functools import reduce
def add(x, y):
return x + y
reduce(add, [1, 2, 3, 4, 5])

输出:15

当然求和运算可以直接用Python内建函数sum(),没必要动用reduce。

但是如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场:

from functools import reduce

def fn(x, y):
return x * 10 + y
r=reduce(fn, [1, 3, 5, 7, 9])
print(r)

输出:13579

做个练习,利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:[‘adam’, ‘LISA’, ‘barT’],输出:[‘Adam’, ‘Lisa’, ‘Bart’]:

def normalize(name):
return name.upper()[0:1] + name.lower()[1:]

L1 = [‘adam’, ‘LISA’, ‘barT’]
L2 = list(map(normalize, L1))
print(L2)

写完第一个版本后,虽然完成了需求,但是其实有可以优化的地方
觉得下面的写法更pythonic些

def normalize(name):
this_name = name.lower()
return this_name[0:1].upper() + this_name[1:].lower()

L1 = [‘adam’, ‘LISA’, ‘barT’]
L2 = list(map(normalize, L1))
print(L2)

第二个练习: Python提供的sum()函数可以接受一个list并求和,请编写一个prod()函数,可以接受一个list并利用reduce()求积:

from functools import reduce

def fn(x, y):
return x * y

def prod(L):
return reduce(fn, L)

print(“3 * 5 * 7 * 9 =”, prod([3, 5, 7, 9]))

4 filter

Python内建的filter()函数用于过滤序列。

和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

例如,在一个list中,删掉偶数,只保留奇数,可以这么写:

def is_odd(n):
return n % 2 == 1
L=list(filter(is_odd, [1,2,3,4,5,6,10,15]))
print(L)

5 sorted

排序也是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。

Python内置的sorted()函数就可以对list进行排序:

print(sorted([36, 5, -12, 9, -21]))
输出:[-21, -12, 5, 9, 36]

此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序

print(sorted([36, 5, -12, 9, -21], key=abs))
输出:[5, 9, -12, -21, 36]

评 论