python 迭代器和生成器

迭代器

 

1.迭代器简述

         什么是迭代器?迭代器是访问集合元素的一种方式。它为类序列对象提供了一个类序列的接口。迭代器对象从集合的第一个元素开始访问,知道所有的元素被访问完结束。同时迭代器只能往前不会后退。

迭代器特点:

  • 提供了可扩展的迭代器接口
  • 对列表的迭代对性能上进行了提升
  • 对字典的迭代中对性能进行了提升
  • 创建了真正的迭代接口,不是原来的随即对象访问
  • 迭代器不能回退,只能向前进行迭代

2.使用迭代器

使用内建的函数iter可以得到一个迭代器对象,使用迭代器的next()方法可以访问下一个元素,如果已经读取了全部的元素,再次执行next()方法就会引发一个StopIteration的异常,Python是根据是否检查到这个异常来决定是否停止迭代的。感觉有点粗暴,呵呵

实例:

In [15]: iter_test = range(3)

In [16]: test = iter(iter_test)

In [17]: test
test     test.py  

In [17]: test
Out[17]: <listiterator at 0x1d2fcd0>

In [18]: test.next()
Out[18]: 0

In [19]: test.next()
Out[19]: 1

In [20]: test.next()
Out[20]: 2

In [21]: test.next()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-21-0743161fe2fe> in <module>()
----> 1 test.next()

StopIteration: 

In [22]:

 

如果我们使用next()的方式去遍历一个迭代器,那是比较麻烦的,还要去判断是否结束这个迭代。那么其实for循环可以直接遍历一个迭代器,它会自动调用迭代器的next()方法和检查StopIteration异常的工作

实例:

In [22]: iter_for = ['list1','list2','list3','list4']

In [23]: IterForGet = iter(iter_for) 


In [24]: IterForGet = iter(iter_for)

In [25]: for li in IterForGet:
    print li
   ....:     
list1
list2
list3
list4



In [28]: IterForGet
Out[28]: <listiterator at 0x1c59ad0>

In [29]: IterForGet.next()      #如果此时再执行next()就会报异常,这点与列表对象是不同的
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-29-beac77e5c4ac> in <module>()
----> 1 IterForGet.next()

StopIteration: 

In [30]:

 

在使用迭代器循环可以避开索引,但有时会需要使用索引方式,我们可以使用enumerate函数,它会以元组的形式返回。

In [30]: iter_for = ['list1','list2','list3','list4']

In [31]: for li,listname in enumerate(iter_for):
   ....:     print li,listname
   ....:     
0 list1
1 list2
2 list3
3 list4

 

列表解析表达式

列表解析表达式可以取代map()和lambda,从效率上来看并且要比前两者更高。列表解析式会返回一个List类型,使用方式[]包括

迭代的对象并返回一个列表。

 

基本使用方式

In [43]: [x for x in range(10)]
Out[43]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [44]:

 

 

可以用If集合

In [40]: [ name for name in ['luodi','liming','ceshi'] if name == 'luodi' ]
Out[40]: ['luodi']



In [42]: [x for x in range(10) if x==5 ]
Out[42]: [5]

In [43]:

 

生成器

生成器(Generator)是一种迭代器,它实现一边循环一边计算,比较节省内存空间。生成器拥有next方法并且行为与迭代器完全相同,这意味着生成器也可以用于Python的for循环中。另外,对于生成器的特殊语法支持使得编写一个生成器比自定义一个常规的迭代器要简单不少,所以生成器也是最常用到的特性之一。如何创建一个生成器呢?

 

1.创建生成器

简单的方式是只需要把列表解析表达式的[]改成()即可

 

In [50]: v=[x+100 for x in range(10)]    #列表解析式

In [51]: v
Out[51]: [100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
 
In [52]: v=(x+100 for x in range(10))   #生成器

In [53]: v
Out[53]: <generator object <genexpr> at 0x1d35af0>

In [54]:

 

上面提到生成器也是迭代器,所以生成器也包含next()方法

In [54]: v.next()
Out[54]: 100

In [55]: v.next()
Out[55]: 101

 

同时也可以使用enumerate函数

In [57]: for k,v in enumerate(v):
             print k,v
   ....:     
0 102
1 103
2 104
3 105
4 106
5 107
6 108
7 109

In [58]:

 

2.yield关键字

什么是yield,一开始学python一脸懵B,其实 yield 的作用就是把一个函数变成一个 generator,并且带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator。

 

In [58]: def EchoRoddy():
   ....:     for i in 'www.roddypy.com':
   ....:         yield i
   ....:         

In [59]:

 

 

In [59]: v=EchoRoddy()

In [60]: v.
v.close       v.gi_code     v.gi_frame    v.gi_running  v.next        v.send        v.throw       

In [60]: v.
v.close       v.gi_code     v.gi_frame    v.gi_running  v.next        v.send        v.throw       

In [60]: v.next()
Out[60]: 'w'

In [61]: v.next()
Out[61]: 'w'

In [62]: v.next()
Out[62]: 'w'

迭代完成后会引发一个StopIteration错误

 

参考资料:http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/