一、函数式编程
函数式编程并非用函数编程这么简单,而是将计算机的运算视为数学意义上的运算,比起面向过程,函数式更加注重的是执行结果而非执行的过程,代表语言有:Haskell、Erlang。而python并不是一门函数式编程语言,但是仍为我们提供了很多函数式编程好的特性,如lambda,map,reduce,filter
二、 匿名函数与lambda
对比使用def关键字创建的是有名字的函数,使用lambda关键字创建则是没有名字的函数,即匿名函数,语法如下
lambda 参数1,参数2,...: expression
举例
# 1、定义
lambda x,y,z:x+y+z
#等同于
def func(x,y,z):
return x+y+z
# 2、调用
# 方式一:
res=(lambda x,y,z:x+y+z)(1,2,3)
# 方式二:
func=lambda x,y,z:x+y+z # “匿名”的本质就是要没有名字,所以此处为匿名函数指定名字是没有意义的
res=func(1,2,3)
匿名函数与有名函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,所以匿名函数用于临时使用一次的场景,匿名函数通常与其他函数配合使用,我们以下述字典为例来介绍它
salaries={
'siry':3000,
'tom':7000,
'lili':10000,
'jack':2000
}
要想取得薪水的最大值和最小值,我们可以使用内置函数max和min(为了方便开发,python解释器已经为我们定义好了一系列常用的功能,称之为内置的函数,我们只需要拿来使用即可)
>>> max(salaries)
'tom'
>>> min(salaries)
'jack'
内置max和min都支持迭代器协议,工作原理都是迭代字典,取得是字典的键,因而比较的是键的最大和最小值,而我们想要的是比较值的最大值与最小值,于是做出如下改动
# 函数max会迭代字典salaries,每取出一个“人名”就会当做参数传给指定的匿名函数key,
# 然后将匿名函数的返回值当做比较依据,最终返回薪资最高的那个人的名字
>>> max(salaries,key=lambda k:salaries[k])
'lili'
# 原理同上
>>> min(salaries,key=lambda k:salaries[k])
'jack'
sorted()方法 会产生新的内存地址(列表和字典都会) 而 .sort() 方法不会,,字典没有 .sort()方法
同理,我们直接对字典进行排序,默认也是按照字典的键去排序的
>>> sorted(salaries)
# ['jack', 'lili', 'siry', 'tom']
res=sorted(salaries,key=lambda k:salaries[k],reverse=True)
print(res) # ['lili', 'tom', 'siry', 'jack']
三、 map、reduce、filter
函数map、reduce、filter都支持迭代器协议,用来处理可迭代对象,我们以一个可迭代对象array为例来介绍它们三个的用法
array=[1,2,3,4,5]
要求一:对array的每个元素做平方处理,可以使用map函数
map函数可以接收两个参数,一个是函数,另外一个是可迭代对象,具体用法如下
>>> res=map(lambda x:x**2,array)
>>> res
<map object at 0x1033f45f8>
>>>
解析:map会依次迭代array,得到的值依次传给匿名函数(也可以是有名函数),而map函数得到的结果仍然是(map对象)迭代器。
>>> list(res) #使用list可以依次迭代res,取得的值作为列表元素
[1, 4, 9, 16, 25]
案例2, 要求列表的每一位末尾都加上_ds
l=['alex','lxx','wxx','yyy']
from collections.abc import Iterator,Iterable,Generator
res=map(lambda name:name+'_ds',l)
print(isinstance(res,Iterable)) # True
print(isinstance(res,Iterator)) # True
print(isinstance(res,Generator))# False
print(res) # <map object at 0x000001EA4B31B280> 如果是python2 将直接得到列表
print(list(res)) # ['alex_ds', 'lxx_ds', 'wxx_ds', 'yyy_ds']
结论: map对象是迭代器 有__iter__()
和 __next__ ()
方法。
要求二:对array进行合并操作,比如求和运算,这就用到了reduce函数
reduce函数可以接收三个参数,一个是函数,第二个是可迭代对象,第三个是初始值
# reduce在python2中是内置函数,在python3中则被集成到模块functools中,需要导入才能使用
>>> from functools import reduce
>>> res=reduce(lambda x,y:x+y,array)
>>> res
15
解析:
- 没有指定初始值,reduce函数会先迭代一次array得到的值作为初始值,作为第一个值数传给x,然后继续迭代一次array得到的值作为第二个值传给y,运算的结果为3 (1+2)
- 将上一次reduce运算的结果3作为第一个值传给x,然后迭代一次array得到的结果3作为第二个值传给y,依次类推,直到迭代完array的所有元素,得到最终的结果15
也可以为reduce指定初始值
>>> res=reduce(lambda x,y:x+y,array,100)
>>> res
115
要求三:对array进行过滤操作,这就用到了filter函数,比如过滤出大于3的元素fliter 函数接收两个参数 第一个参数可以返回bool值的过滤条件(True or False) 第二个是可迭代对象 ,得到的结果类似map ,仍为迭代器
>>> res=filter(lambda x:x>3,array)
解析:filter函数会依次迭代array,得到的值依次传给匿名函数,如果匿名函数的返回值为真,则过滤出该元素,而filter函数得到的结果仍然是迭代器。
>>> list(res)
[4, 5]
案例2
# 方式一
l=['alex_sb','lxx_sb','wxx','张良']
res=(name for name in l if name.endswith('sb'))
print(res) # <generator object <genexpr> at 0x00CFF8B0>
# 方式二
res=filter(lambda name:name.endswith('sb'),l)
print(res) # <filter object at 0x000002582FBEB100>
print(isinstance(res,Iterable)) # True
print(isinstance(res,Iterator)) # True
print(isinstance(res,Generator)) # False
提示:我们介绍map、filter、reduce只是为了带大家了解函数式编程的大致思想,在实际开发中,我们完全可以用列表生成式或者生成器表达式来实现三者的功能。