生成器、lamda表达式及map、reduce、filter函数 .

来源:互联网 发布:万国数据外资企业 编辑:程序博客网 时间:2024/05/22 13:29

 

转自:http://blog.csdn.net/chlele0105/article/details/18151517

在讲解map、reduce、filter函数之前,我们先来了解一下迭代器对象(iterable object)和生成器的相关概念

1. 迭代对象(iterable object)

迭代对象是这样一个对象,它包含有一个next()方法(__next__()方法,在python 3x中), 这个方法的目的是进行到下一个结果,而在结束一系列结果之后,抛出StopIteration错误

当一个循环结构(比如for)调用循环对象时,它就会每次循环的时候调用next()方法,直到StopIteration出现,for循环接收到,就知道循环已经结束,停止调用next()。

假设我们有test.txt文件,里面包含以下内容:

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. 123  
  2. abc  
  3. 456  

当我们调用:

>>>f.open('test.txt')

>>>f.next()

>>>f.next()

..

不断地输入f.next(),直到最后出现StopIteration

open()返回的实际上是一个循环对象,包含有next()方法。而该next()方法每次返回的就是新的一行的内容,到达文件结尾时举出StopIteration。这样,我们相当于手工进行了循环。

自动进行的话,就是:

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. for line in open('test.txt'):  
  2.     print line  

在这里,for结构自动调用next()方法,将该方法的返回值赋予给line。循环知道出现StopIteration的时候结束。

相对于序列,用迭代对象来控制循环的好处在于:可以不用在循环刚开始的时候,就生成所有的元素。所使用的元素在循环过程中逐次生成。这样,就节省了空间,提高了效率,并提高编程的灵活性。

iter()函数和迭代器(iterator)

从技术上来说,迭代对象和for循环调用之间还有一个中间层,就是要将迭代对象转换成迭代器(iterator)。这一转换是通过使用iter()函数实现的。但从逻辑层面上,常常可以忽略这一层,所以迭代对象和迭代器常常相互指代对方。


2. 生成器(generator)


生成器的主要目的是构成一个用户自定义的循环对象。

生成器的编写方法和函数定义类似,只是在return的地方改为yield。生成器中可以有多个yield。当生成器遇到一个yield时,会暂停运行生成器,返回yield后面的值。当再次调用生成器的时候,会从刚才暂停的地方继续运行,直到下一个yield。生成器自身又构成一个迭代器,每次迭代时使用一个yield返回的值。

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. def gen():  
  2.     a = 100  
  3.     yield a  
  4.     a = a*8  
  5.     yield a  
  6.     yield 1000  
该生成器共有三个yield, 如果用作循环器时,会进行三次循环。
[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. for i in gen():  
  2.     print i  
再考虑如下一个生成器:

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. def gen():  
  2.     for i in range(4):  
  3.         yield i  


3.生成器表达式


    当序列过长, 而每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析。因为列表解析返回一个列表,而生成器表达式则返回一个生成器,节约内存,效率更高。

生成器表达式的语法和列表解析一样,只不过生成器表达式是被()括起来的,而不是[]


上述生成器又可以写成生成器表达式(Generator Expression):

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. G = (x for x in range(4))  

4. filter()

filter(bool_func,seq):此函数的功能相当于过滤器,调用一个布尔函数bool_func来迭代遍历每个seq中的元素;返回一个使bool_seq返回值为true的元素的序列

     例如:

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. >>> filter(lambda x : x%2 == 0,[1,2,3,4,5])    
  2. [24]    


5. map()

map(func,seq):将seq中的元素依次执行func(item),将结果组成一个list返回;如果func为None,func表现为身份函数,返回一个含有每个序列中元素集合的n个元组的列表。

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. >>> map(lambda x : None,[1,2,3,4])    
  2. [NoneNoneNoneNone]    
  3. >>> map(lambda x : x * 2,[1,2,3,4])    
  4. [2468]    
  5. >>> map(lambda x : x * 2,[1,2,3,4,[5,6,7]])    
  6. [2468, [567567]]    
  7. >>> map(lambda x : None,[1,2,3,4])    
  8. [NoneNoneNoneNone]   
另外map也支持多个sequence,这就要求function也支持相应数量的参数输入:

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. >>> def add(x, y): return x+y   
  2. >>> map(add, range(8), range(8))   
  3. [02468101214]  

6. reduce()

reduce(func,seq[,init]):func为二元函数,将func作用于seq序列的元素,每次携带一对(先前的结果以及下一个序列的元素),连续的将现有的结果和下一个值做运算,然后再将得到的结果作用随后的序列元素上,最终返回一个单一值。如果初始值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素。

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. >>> reduce(lambda x,y : x + y,[1,2,3,4])    
  2. 10    
  3. >>> reduce(lambda x,y : x + y,[1,2,3,4],10)    
  4. 20    


[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. >>> def add(x,y): return x + y   
  2. >>> reduce(add, range(111))   
  3. 55 (注:1+2+3+4+5+6+7+8+9+10)  
  4. >>> reduce(add, range(111), 20)   
  5. 75 (注:1+2+3+4+5+6+7+8+9+10+20)  


lambda:这是Python支持一种有趣的语法,它允许你快速定义单行的最小函数,类似与C语言中的宏,这些叫做lambda的函数,是从LISP借用来的,可以用在任何需要函数的地方:

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. >>> g = lambda x: x * 2   
  2. >>> g(3)   
  3. 6 <SPAN style="FONT-SIZE: 12px">  
  4. >>> (lambda x: x * 2)(3) </SPAN>  
  5. 6  


7. 函数作为参数传递

函数可以作为一个对象进行参数传递。函数名(比如func)即指向该对象,不需要括号。比如说:

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <SPAN style="FONT-FAMILY: SimSun; FONT-SIZE: 12px">def test(f, a, b):  
  2.     print 'test'  
  3.     print f(a, b)  
  4.   
  5. test(func, 35)</SPAN>  

我们可以看到,test函数的第一个参数f就是一个函数对象。我们将func传递给f,那么test中的f()所做的实际上就是func()所实现的功能。

这样,我们就大大提高了程序的灵活性。假设我们有另一个函数取代func,就可以使用相同的test函数了。如下:

[python] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. test((lambda x,y: x**2 + y), 69)  
0 0
原创粉丝点击