函数式编程
函数式编程(Functional Programming),是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量。因此,任意一个函数,只要输入是确定的,输出就是确定的。
函数式编程是一种"编程范式"(programming paradigm)。它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
更多内容
廖雪峰Python教程 函数式编程
函数式编程初探 - 阮一峰
函数式编程 - 看云
函数式编程 - 百度百科
高阶函数
函数式编程中,可以将函数当作变量一样使用。接受函数为参数,或者把函数作为结果返回的函数称为高阶函数(Higher-order Functions) 。
def double(x):
return 2 * x
def square(x):
return x * x
def func(g, arr):
return [g(x) for x in arr]
arr1 = func(double, [1, 2, 3, 4])
arr2 = func(square, [1, 2, 3, 4])
arr1
[2, 4, 6, 8]arr2
[1, 4, 9, 16]
map()/reduce()/filter()/sorted() /apply() 是 Python 中较为常用的高阶函数,它们为函数式编程提供了不少便利。
Python 3 中,map 和 filter 还是内置函数,但是由于引入了列表推导和生成器表达式,它们变得没那么重要了。列表推导或生成器表达式具有 map 和 filter 两个函数的功能,而且更易于阅读。apply 函数在Python 2.3 中标记为过时,在Python 3 中移除了,因为不再需要它了。如果想使用不定量的参数调用函数,可以编写 fn(*args, **keywords),不用再编写 apply(fn, args,kwargs)。
map()
map 函数将传入的函数依次作用到序列的每个元素,并把结果作为新的 Iterator 返回。map 函数语法:
map(function, iterable, …)
参数 —— function : 函数 ; iterable : 一个或多个序列
返回值 —— Python 2.x 返回列表; Python 3.x 返回迭代器(map)
def square(x): # 计算平方数
return x ** 2
map(square, [1,2,3,4,5]) # 计算列表各个元素的平方
<map object at 0x000001B9F81ADEB8>map(lambda x: x ** 2, [1, 2, 3, 4, 5]) # 使用 lambda 匿名函数
[1, 4, 9, 16, 25] # python2输出结果
<map object at 0x000001B9F81ADEB8> # python3输出结果(可使用list()函数对map函数返回结果进行转换)
list(map(lambda x: x ** 2, [1, 2, 3, 4, 5]))
[1, 4, 9, 16, 25]
map实现list的值的格式批量转换
list(map(str, [1, 2, 3, 4]))
[‘1’, ‘2’, ‘3’, ‘4’]list(map(int, [‘1’, ‘2’, ‘3’, ‘4’]))
[1, 2, 3, 4]
提供了两个列表,对相同位置的列表数据进行相加
map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
[3, 7, 11, 15, 19]
-------- 列表推导式实现上述功能 -----------
[square(n) for n in [1,2,3,4,5]]
[1, 4, 9, 16, 25][str(n) for n in [1,2,3,4]]
[‘1’, ‘2’, ‘3’, ‘4’][int(n) for n in [‘1’, ‘2’, ‘3’, ‘4’]]
[1, 2, 3, 4]
reduce()
reduce() 函数会对参数序列中元素进行累积。函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce() 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果后继续和序列的下一个元素做累积计算,直到累积到列表最后一个数据。Python 2 中,reduce 是内置函数,但是在Python 3 中放到functools 模块里了。reduce() 函数语法:
reduce(function, iterable[, initializer])
参数 —— function:函数,有两个参数; iterable : 可迭代对象; initializer:可选,初始参数
返回值 —— 返回函数计算结果。
序列求和实现
from functools import reduce # Python3 需要引入
def add(x, y) : # 两数相加(或使用 from operator import add)
return x + y
reduce(add, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5
15reduce(lambda x, y: x * y, [1, 2, 3, 4]) # 相当于 ((1 * 2) * 3) * 4
24reduce(lambda x, y: x * y, [1, 2, 3, 4], 5) # ((((5 * 1) * 2) * 3)) * 4
120reduce(lambda x, y: x / y, [2, 3, 4], 72) # (((72 / 2) / 3)) / 4
3reduce(lambda x, y: x + y, [1, 2, 3, 4], 5) # ((((5 + 1) + 2) + 3)) + 4
15reduce(lambda x, y: x - y, [8, 5, 1], 20) # ((20 - 8) - 5) - 1
6f = lambda a, b: a if (a > b) else b # 两两比较,取最大值
reduce(f, [5, 8, 1, 10])
10
** 注意:** 在 Python3 中,reduce() 函数已经被从全局名字空间里移除了,它现在被放置在 fucntools 模块里,如果想要使用它,则需要通过引入 functools 模块来调用 reduce() 函数:
from functools import reduce
filter()
filter() 函数用于过滤序列,过滤掉不符合条件的元素,Python2返回过滤后的列表,Python3返回迭代器对象(filter),如果要转换为列表,可以使用 list() 来转换。
filter(function, iterable)
参数 —— function : 判断函数; iterable : 可迭代对象
返回值 —— 返回一个迭代器对象
过滤出列表中的所有奇数
def is_odd(n) :
return n % 2 == 1
list(filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
[1, 3, 5, 7, 9]
过滤出1~100中平方根是整数的数
import math
def is_sqr(n) :
return math.sqrt(n) % 1 == 0
list(filter(is_sqr, range(1, 101)))
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
注意:Python3 中返回到是一个 filter 类,filter 类实现了 iter 和 next 方法,可以看成是一个迭代器, 有惰性运算的特性,相对 Python2提升了性能,可以节约内存。
sorted()
sorted() 函数对所有可迭代的对象进行排序操作。
sort 与 sorted 区别:
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
sorted() 语法:
sorted(iterable, key=None, reverse=False)
参数 —— iterable – 可迭代对象; key – 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序; reverse – 排序规则,reverse = True 降序 , reverse = False 升序(默认)
返回值 —— 重新排序的列表
sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
使用集合的sort()方法,实现类似结果
a = [5,2,3,1,4]
a.sort()
a
[1,2,3,4,5]
sort()及sorted()的区别在于, sort()返回None,排序操作直接作用在原list上,而sorted()排序后会返回新的list
a = [1,3,2,4];id(a); a.sort(); id(a)
1734959842440
1734959842440b = [4,3,1,2]; id(b);id(sorted(b));
1734959953864
1734959953672
sort()和sorted() 另一个区别在于list.sort() 方法只为 list 定义。而 sorted() 函数可以接收任何的 iterable。
sorted({1: ‘D’, 2: ‘B’, 3: ‘B’, 4: ‘E’, 5: ‘A’})
[1, 2, 3, 4, 5]
利用key进行倒序排序
example_list = [5, 0, 6, 1, 2, 7, 3, 4]
result_list = sorted(example_list, key=lambda x: x * -1)
print(result_list)
[7, 6, 5, 4, 3, 2, 1, 0]
进行反向排序,也可传入第三个参数 reverse=True:
example_list = [5, 0, 6, 1, 2, 7, 3, 4]
sorted(example_list, reverse=True)
[7, 6, 5, 4, 3, 2, 1, 0]
返回函数
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
返回累加函数变量
def lazy_sum(*args): # 外部函数
def sum(): #内部函数 可以引用外部函数lazy_sum的参数和局部变量
ax = 0
for n in args:
ax = ax + n
return ax
return sum # 返回函数变量(返回函数sum时,lazy_sum相关参数和变量都保存在返回的函数中,闭包)
f = lazy_sum(1, 3, 5, 7, 9)
f
<function lazy_sum..sum at 0x00000193F3C89048>f() # 返回的函数并没有立刻执行,而是直到调用了f()才执行
25
调用lazy_sum()时,每次调用都会返回一个新的函数
f1 = lazy_sum(1, 3, 5, 7, 9)
f2 = lazy_sum(1, 3, 5, 7, 9)
f1==f2 # f1()和f2()的调用结果互不影响
False
闭包
一个函数返回了一个内部函数,该内部函数引用了外部函数的相关参数和变量,我们把该返回的内部函数称为闭包(Closure)
闭包的最大特点就是引用了自由变量,即使生成闭包的环境已经释放,闭包仍然存在。
闭包在运行时可以有多个实例,即使传入的参数相同。
调用lazy_sum()时,每次调用都会返回一个新的函数
f1 = lazy_sum(1, 3, 5, 7, 9)
f2 = lazy_sum(1, 3, 5, 7, 9)
f1 == f2 # f1()和f2()的调用结果互不影响
False
利用闭包,还可以模拟类的实例。
构造一个类,用于求一个点到另一个点的距离:
from math import sqrt
class Point(object):
def init(self, x, y):
self.x, self.y = x, y
def get_distance(self, u, v):
distance = sqrt((self.x - u) ** 2 + (self.y - v) ** 2)
return distance
pt = Point(7, 2) # 创建一个点
pt.get_distance(10, 6) # 求到另一个点的距离
5.0
用闭包来实现:
def point(x, y):
def get_distance(u, v):
return sqrt((x - u) ** 2 + (y - v) ** 2)
return get_distance
pt = point(7, 2)
pt(10, 6)
5.0
注意: 尽量避免在闭包中引用循环变量,或者后续会发生变化的变量。
def count():
funcs = []
for i in [1, 2, 3]:
def f():
return i
funcs.append(f)
return funcs
f1, f2, f3 = count()
f1()
3f2()
3f3()
3
原因在于上面的函数 f 引用了变量 i,但函数 f 并非立刻执行,当 for 循环结束时,此时变量 i 的值是3,funcs 里面的函数引用的变量都是 3,最终结果也就全为 3。
可以再创建一个函数,并将循环变量的值传给该函数
def count():
funcs = []
for i in [1, 2, 3]:
def g(param):
f = lambda : param # 这里创建了一个匿名函数
return f
funcs.append(g(i)) # 将循环变量的值传给 g
return funcs
f1, f2, f3 = count()
f1()
1f2()
2f3()
3