高阶函数python结合使用代码_Python函数式介绍一 - 高阶函数

最近为了给朋友推广Python函数式编程,特意准备写一系列文章,当然我不敢说自己已经把函数式琢磨透了,我觉得在我在函数式编程这道路上还有很长的路需要走。

我们还是从高阶函数入手吧,比较容易突破。

在这里我们会用到lambda函数也就是匿名函数,我们就理解成是没有名字的函数把。

map

students = [

{

"name":"wwb",

"sex":"1",

"course":[

{

"name":"Math",

"score":90

},

{

"name":"English",

"score":80

}

]

},

{

"name":"wxa",

"sex":"1",

"course":[

{

"name":"Music",

"score":90

},

{

"name":"English",

"score":80

}

]

},

{

"name":"wxb",

"sex":"1",

"course":[

{

"name":"Math",

"score":90

},

{

"name":"Music",

"score":80

}

]

},

]

以上是我们需要测试的数据,我们做一个稍微简单的需求,求选修数学的学生。

先一步一步来,把问题分解,看以下数据

_course = [

{

"name":"Math",

"score":90

},

{

"name":"Music",

"score":80

}

]

求_course各个课程是否为Math,只需要一行

print(list(map(lambda it:it["name"]=="Math",_course)))

'''

结果:

[True,False]

'''

any,all

先看结果

print(any(map(lambda it:it["name"]=="Math",_course)))

print(all(map(lambda it:it["name"]=="Math",_course)))

print(any((True,True,True,False)))

print(any((False,False)))

print(all((True,True,True)))

print(all((True,False)))

'''

结果:

True

False

True

False

True

False

'''

any函数传入的集合中一个为True则any结果为Ture,若集合全为Flase则结果为False

all函数传入的集合必须所有都为True结果才为True,否则为False

求_course中是否包含Math,只需要一行

print(any(map(lambda it:it["name"]=="Math",_course)))

'''

结果:

True

'''

惰性求值

请看以下例子

print("test1")

print(map(lambda it:it["name"]=="Math",_course))

print("test2")

print(list(map(lambda it:it["name"]=="Math",_course)))

def fun0(it):

print(it)

return it["name"]=="Math"

print("test3")

"执行所有操作"

print(any(list(map(fun0,_course))))

print("test4")

"map并没有执行完所有元素,遇到一个true直接返回"

print(any(map(fun0,_course)))

'''

结果:

test1

test2

[True, False]

test3

{'name': 'Math', 'score': 90}

{'name': 'Music', 'score': 80}

True

test4

{'name': 'Math', 'score': 90}

True

'''

我们直接把map结果打印出来会发现是一个map对象,事实上这个对象还没有做任何操作,如果我们对map对象执行list操作,这个时候map处理集合的数据。test4可以发现any一旦遇到True就直接返回了,剩下的元素map不会去处理。

这个特性叫惰性求值,当我们真的需要map object的结果的时候,map才会开始对元素进行加工处理。而且是需要map object一个元素,map就处理一个元素,一个都不会处理多。这个就保证了不会浪费cpu的资源,当我map一个1000个元素的集合,实际上我只取其中的一个返回值,则python是不会浪费cpu去处理剩下的999个元素的。

如果你list一个map对象,则map会操作集合的所有元素,返回一个结果集合。看这个是不是就是数学映射的概念?一个集合转化成另一个一一对应的集合。所以python把这个操作取名为map也就是映射的意思。

filter

filter函数和它的名字一样做的是过滤的操作,在一个集合中筛选出符合条件的数据

求选修数学的同学

def findmath(courses):

return any(map(lambda it:it["name"]=="Math",courses))

print(list(filter(lambda it:findmath(it["course"]),students)))

'''

结果:

[

{

'name': 'wwb',

'sex': '1',

'course':

[

{'name': 'Math', 'score': 90},

{'name':'English', 'score': 80}

]

},

{

'name': 'wxb',

'sex': '1',

'course': [

{'name': 'Math', 'score': 90 },

{'name': 'Music','score': 80 }

]

}

]

'''

reduce

先看一个简单的例子

from functools import reduce

ilist = [1,2,3,4,5,6,7,8,9,10]

print(reduce(lambda acc,it:acc+it,ilist,0))

print(reduce(lambda acc,it:acc+it,ilist))

'''

结果:

55

55

'''

reduce(lambda acc,it:acc+it,ilist,0)

一开始acc为0,it为列表第一项ilist[0],

接着 acc为 (ilist[0] + 0) ,it 为 ilist[1]

接着 acc为 ((ilist[0] + 0) + ilist[1]),it 为 ilist[2]

接着 acc为 (((ilist[0] + 0) + ilist[1])+ilist[2]),it 为 ilist[3]

...

直到最后一项,返回最后一次运行的结果。

一般我称acc为累计值,0为幺元,幺元是一个数学概念,是相对运算而来的,比如

0是加减法的幺元,任何元素(+或-) 0 都等于本身

1是乘除法的幺元,任何元素(*或/) 1 都等于本身

""是字符串加法的幺元,任何字符串(除了NULL)加 "" 都等于本身

一般我都习惯在reduce函数加上幺元,reduce也支持不加幺元的情况,不加幺元则,acc初始值为集合的第一个元素

reduce(lambda acc,it:acc+it,ilist)

一开始acc为ilist[0],it为列表第一项ilist[1],

接着 acc为 (ilist[0] + ilist[1]),it 为 ilist[2]

...

直到最后一项,返回最后一次运行的结果。

如果不传幺元则当列表ilist有0个元素的时候,reduce函数会报错

统计选修数学平均分

我们简化下问题,不然又再学几个新函数,我们就用上面学过的map/filter/any/reduce函数

以下是选修数学的学生的数学成绩

studentmaths=[

{

"name":"wwb",

"sex":1,

"score":90,

},

{

"name":"wxa",

"sex":1,

"score":91,

},

{

"name":"wxb",

"sex":0,

"score":92,

},

{

"name":"wxc",

"sex":0,

"score":93,

},

{

"name":"wxd",

"sex":0,

"score":94,

},

]

求总分

print(reduce(lambda acc,it:acc+it["score"],studentmaths,0))

'''

结果:

460

'''

求平均分

print(reduce(lambda acc,it:acc+it["score"],studentmaths,0)/len(studentmaths))

'''

结果:

92.0

'''

打印班上所有同学的成绩

print(reduce(lambda acc,it:acc + "name:%s,score:%d\r\n"%(it["name"],it["score"]),studentmaths,""))

'''

结果:

name:wwb,score:90

name:wxa,score:91

name:wxb,score:92

name:wxc,score:93

name:wxd,score:94

'''

我们来看一个复杂的幺元,求女生平均分

temp = reduce(lambda acc,it: { "sum":acc["sum"]+it["score"],"count":acc["count"]+1},filter(lambda s:s["sex"]==0,studentmaths),{"sum":0,"count":0})

print(temp)

print(temp["sum"]/temp["count"])

'''

结果:

{'sum': 279, 'count': 3}

93.0

'''

当然可以更简单些,以上写法是为了解释幺元,展示reduce的复杂写法,其实就这个例子而论,没什么必要这么写,可以写成以下简单的写法

fstudentmaths = list(filter(lambda s:s["sex"]==0,studentmaths))

print(reduce(lambda acc,it:acc+it["score"],fstudentmaths,0)/len(fstudentmaths))

'''

结果:

93.0

'''

打印男生成绩单

print(reduce(lambda acc,it:acc + "name:%s,score:%d\r\n"%(it["name"],it["score"]),filter(lambda s:s["sex"]==1,studentmaths),""))

'''

结果:

name:wwb,score:90

name:wxa,score:91

'''

总结

利用python自带的map/filter/reduce/all/any函数我们可以改写大部分for/while循环。我们利用python的这个高级函数你会发现你的思维方式会发生改变,你会习惯这种集合转化来转化去的思维。

而for/while则是串行的,逐个处理的思想。自己写for/while其实很容易出错的,用高级函数都是一些简单的lambda函数组合在一起,想出错也不太容易。

我个人认为程序结构,顺序、条件、循环,循环是最复杂的结构,如果一段程序中嵌套三四个循环,每个循环几百行,那这段代码基本不用看了。高阶函数是用集合的观点来处理数据的,化循环为顺序结构,能让程序更容易理解

另外,大家有没有发现最后面函数写得很长很长,而且很不好阅读,没关系,下节我们稍微加工一下,变成链式调用方式

测试代码

我直接把上面的测试代码贴出来吧

from functools import reduce

students = [

{

"name":"wwb",

"sex":"1",

"course":[

{

"name":"Math",

"score":90

},

{

"name":"English",

"score":80

}

]

},

{

"name":"wxa",

"sex":"1",

"course":[

{

"name":"Music",

"score":90

},

{

"name":"English",

"score":80

}

]

},

{

"name":"wxb",

"sex":"1",

"course":[

{

"name":"Math",

"score":90

},

{

"name":"Music",

"score":80

}

]

},

]

_course = [

{

"name":"Math",

"score":90

},

{

"name":"Music",

"score":80

}

]

"是否选修数学课"

print(map(lambda it:it["name"]=="Math",_course))

"显示结果"

print(list(map(lambda it:it["name"]=="Math",_course)))

"all,any"

print(any(map(lambda it:it["name"]=="Math",_course)))

print(all(map(lambda it:it["name"]=="Math",_course)))

"惰性求值测试"

def fun0(it):

print(it)

return it["name"]=="Math"

"执行所有操作"

print(any(list(map(fun0,_course))))

"map并没有执行完所有元素,遇到一个true直接返回"

print(any(map(fun0,_course)))

"filter"

"找出选修数学的所有学生"

def findmath(courses):

return any(map(lambda it:it["name"]=="Math",courses))

print(list(filter(lambda it:findmath(it["course"]),students)))

"reduce"

"统计选修数学平均分"

"以下是选修数学的学生的数学成绩"

studentmaths=[

{

"name":"wwb",

"sex":1,

"score":90,

},

{

"name":"wxa",

"sex":1,

"score":91,

},

{

"name":"wxb",

"sex":0,

"score":92,

},

{

"name":"wxc",

"sex":0,

"score":93,

},

{

"name":"wxd",

"sex":0,

"score":94,

},

]

"reduce简单例子"

ilist = [1,2,3,4,5,6,7,8,9,10]

print(reduce(lambda acc,it:acc+it,ilist,0))

print(reduce(lambda acc,it:acc+it,ilist))

"总分"

print(reduce(lambda acc,it:acc+it["score"],studentmaths,0))

"平均分"

print(reduce(lambda acc,it:acc+it["score"],studentmaths,0)/len(studentmaths))

"把班上同学的成绩打印出来"

print(reduce(lambda acc,it:acc + "name:%s,score:%d\r\n"%(it["name"],it["score"]),studentmaths,""))

"女生平均分"

temp = reduce(lambda acc,it: { "sum":acc["sum"]+it["score"],"count":acc["count"]+1},filter(lambda s:s["sex"]==0,studentmaths),{"sum":0,"count":0})

print(temp)

print(temp["sum"]/temp["count"])

"更简单些写法"

fstudentmaths = list(filter(lambda s:s["sex"]==0,studentmaths))

print(reduce(lambda acc,it:acc+it["score"],fstudentmaths,0)/len(fstudentmaths))

"男生成绩单"

print(reduce(lambda acc,it:acc + "name:%s,score:%d\r\n"%(it["name"],it["score"]),filter(lambda s:s["sex"]==1,studentmaths),""))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值