map、reduce、filter、list comprehension和generator expression 有一些共同点,就是接收两个参数,一个是函数,一个是序列,将传入的函数依次作用到序列的每个元素。把函数作为参数传入,或者把函数作为返回值返回,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。
Map函数:
原型:map(function, sequence),作用是将一个列表根据同一个函数映射到另一个列表,这是一种对应关系。map函数得到的结果还是原来单元数量的一个新列表。但是每个单元的类型可能不同,例如:源列表是一个整数列表,得出的结果列表可能是列表的列表,源列表和结果列表在第一层是单元个数相同的。如果函数支持n个参数,那map函数可以支持n个序列,注意各序列的长度必须一样,否则报错。
使用方法:def foo(x):
return x**2
print map(foo,range(1,10))
#结果是:
[1, 4, 9, 16, 25, 36, 49, 64, 81]
def foo2(x):
return [x,x**2]
print map(foo2,range(1,6))
#结果是:
[[1, 1], [2, 4], [3, 9], [4, 16], [5, 25]]
def foo3(x,y,z):
return x+y+z
print map(foo3,range(1,5),range(10,50,10),range(100,500,100))
#结果是:
[111, 222, 333, 444]
Reduce函数
原型:reduce(function, sequence, startValue),作用是将一个列表归纳为一个输出。对sequence中的item顺序迭代调用function,函数必须要有2个参数。要是有第3个参数,则表示初始值,可以继续调用初始值,返回一个值。注意这里的startValue只是第一个作为函数foo4(x,y)第一个参数,x位置。从y开始迭代sequence里边的数据作为参数。如果没有startValue,那么将从x开始迭代sequence。
使用方法:def foo4(x,y):
return x+y**2
def foo5(x,y):
return x**2+y
print reduce(foo4,range(1,4),5)
print reduce(foo5,range(1,4),5)
#结果是:
19 # 5+1**2+2**2+3**2 从这里可以看出来startValue是初始迭代数据。
459687 # ((5**2+1)**2+2)**2+3,从这里可以看出来startValue是初始迭代数据。
Filter函数
原型:filter(function, sequence),对sequence中的item依次执行function(item),将执行结果为True(!=0)的item组成一个新的sequence。sequence的类型(List/String/Tuple)没有变。len(结果) <= len(源sequence)。注意函数的返回值必须是布尔型。
使用方法:def foo6(n):return not(n=='z' or n== 'Z')
print filter(foo6,'Zhanzhangzhijia')
#结果是:
hanhanghijia
def foo7(x):return x%2
print filter(foo7,range(1,10))
#结果是:
[1, 3, 5, 7, 9]
Lambda函数
原型:lambda : 函数体,隐函数,快速定义单行的最小函数。该函数没有函数名称,但是可以将它赋值给一个变量进行调用。lambda 函数只是一种风格问题,不一定非要使用它们;任何能够使用它们的地方,都可以定义一个单独的普通函数来进行替换。我将它们用在需要封装特殊的、非重用代码上,避免代码充斥着大量单行函数。lambda 真是个很漂亮的函数。
使用方法:tmp = lambda x: x ** 2
print tmp(6)
print (lambda x: x ** 2)(6)
#结果是:
36
36
列表解析(列表推导式,list comprehension)
Python 的强大特性之一是其对 list 的解析,它提供一种紧凑的方法,可以通过对 list 中的每个元素应用一个函数,从而将一个 list 映射为另一个 list。列表解析比 for 更精简,运行更快,特别是对于较大的数据集合,列表解析可以替代绝大多数需要用到 map和 filter的场合。
基本形式:[x for item in sequence ], 这里x表示对item的操作,if可以作为过滤条件。
使用方法:print [x**2 for x in range(1,10)]
print [x**2 for x in range(1,10) if x**2<50]
#结果是:
[1, 4, 9, 16, 25, 36, 49, 64, 81]
[1, 4, 9, 16, 25, 36, 49]
print [x+y for x in range(1,4) for y in range(100,400,100)]
print [y+x for x in range(1,4) for y in range(100,400,100)]
print [y+x for x in range(100,400,100) for y in range(1,4)]
#结果是:
[101, 201, 301, 102, 202, 302, 103, 203, 303]
[101, 201, 301, 102, 202, 302, 103, 203, 303]
[101, 102, 103, 201, 202, 203, 301, 302, 303]
#前边for的变量取一个值,固定之后,迭代后边for的变量。与在表达式出现的先后顺序无关。
生成器表达式(generator expression)
生成器表达式和列表解析很像,所不同的是生成器表达式并不是在一开始就计算所有的元素,而是只有需要的时候才展开特定的部分,这可以大大的节省系统资源。所以除非你明确希望返回列表,否则应该始终使用生成器表达式,尤其是表达式成员非常巨大的时候。
生成器表达式的语法和列表解析一样,只不过生成器表达式是被()括起来的,而不是[ ]。import time
def ganeraterFoo(a):
foo = ((x*y for x in range(1,y+1)) for y in range(1,a+1))
re =0
for x in foo:
for y in x:
re += y
return re
def listFoo(a):
foo = [[x*y for x in range(1,y+1)] for y in range(1,a+1)]
re =0
for x in foo:
for y in x:
re += y
return re
time1 = time.time()
print ganeraterFoo(10000)
time2 = time.time()
print time2-time1
time3 = time.time()
print listFoo(10000)
time4 = time.time()
print time2-time1
print time4-time3
print (time4-time3-time2+time1)/(time4-time3)
#结果是:
1250416704167500
13.1509997845
1250416704167500
13.1509997845
18.5320000648
0.290362630129
#下图中的红色部分是用生成器表达式占用的计算机资源,黄的部分是列表解析占用的计算机资源。
#可见列表解析大量占用了内存资源,可能因为需要在内存中构造整个列表,效率反而低很多。
#生成器表达式并没有显著多占用CPU资源,却大量节省了内存资源
#生成器表达式竟然显著提高运行速度(将近30%),这是意料之外的
#这是在计算机内存占用约60%-70%情况下测得的结果,应该不是应用到计算机缓存的原因。