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 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 <if (conditions)>], 这里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%情况下测得的结果,应该不是应用到计算机缓存的原因。