angrykola

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

迭代器

  • 列表解析与for循环
  • iter与next
  • map、zip与filter迭代器
  • ord函数
  • 矩阵与列表解析
  • 生成器(generator)
  • send与next

列表解析与for循环:

for循环用来遍历迭代对象中的每一个项,会在每次迭代中调用该对象的__next__方法,而且会捕捉StopIteration异常,从而决定何时停止循环。

列表解析和for循环都是迭代工具,列表解析是执行常见for循环的简明并且高效的方案:对可迭代对象内所有元素应用一个表达式,并且收集结果。可以把列表解析转换成for循环,列表解析的部分语法看起来就像是for循环的首行。

#for循环遍历并且修改列表
>>> List = [1,2,3,4,5]
>>> for i in range(len(List)):
    List[i] += 10
>>> List
[11, 12, 13, 14, 15]
#列表解析修改,跟for循环相比,列表解析运用代码更少却更快捷
>>> L = [i + 10 for i in List]
>>> L
[21, 22, 23, 24, 25]

iter和next:

#next方法
>>> i = open('new.txt')
>>> next(i)
'(1)未来10年,经济成长依然是政?权合法性的默认理由和遗训。朝野将继续一致不顾廉耻的赚?钱。\n'
>>> i.__next__()
'(2)金融继续有限度推进开放,但节奏会比WTO设计的慢,金融问题,留待下节讨论。\n'
#使用iter迭代
>>> L = [1,2,3,4,5]  
#列表此时不能使用next方法,会曝TypeError异常
>>> I = iter(L)         #将列表封装进iter
>>> next(I)
1
>>> next(I
2
......
>>> I.__next__()
4
>>> I.__next__()
5
#迭代完毕后如果继续运行,将会弹出StopIteration异常

map、zip、filter迭代器

#map方法
>>> a=(1,2,3)
>>> A = map(abs,a)
>>> next(A)
1
>>> A.__next__()
2

#filter方法
>>> list(filter(bool,['hello','','world','!','over']))
['hello', 'world', '!', 'over']

ord函数

#python的ord函数会返回一个ASCII整数编码
>>> test = 'kola'  
>>> List = []
>>> for x in test:               #通过for循环遍历字符串
    List.append(ord(x))      #通过append,将ord传入列表中
>>> List
[107, 111, 108, 97]

矩阵列表解析

#建立一个列表矩阵
>> M=[[1,2,3],[4,5,6],[7,8,9],[0,0,0]]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [0, 0, 0]]
>>> [row[1] for row in M]  
[2, 5, 8, 0]
>>> [M[row][1] for row in (1,2,3)]
[5, 8, 0]
>>> [M[i][i]for i in range(3)]
[1, 5, 9]
#通过列表解析来混合多个矩阵
>>> N =[[1,1,1],[2,2,2],[3,3,3]]
>>> [M[row][col]*N[row][col]for row in range(3)for col in range(2)]
[1, 2, 8, 10, 21, 24]

理解列表解析:

基于运行在当前python下测试,map调用比等效的for循环要快两倍,二列表解析往往比map调用要稍快一些,速度上的差距是来自于底层实现上,map和列表解析是在解释器中以C语言的速度来运行的,毕python的for循环代码在PVM中进行运行要快的多。

 

生成器(generator)

成器就是一种迭代器拥有next方法并且行为与迭代器完全相同,所以生成器也可以用于Python的for循环中。

#首先创建一个最简单的生成器
>>> def gensquares(N):  #通过gensquares创建生成器
        for i in range(N):
            yield i **2
>>> for i in gensquares(5): #使用for循环遍历,跟迭代器一样
        print(i,end=' : ')
0 : 1 : 4 : 9 : 16 : 

如果想看看for循环里发生了什么,直接调用生成器函数

>>> x = gensquares(5)
>>> x
<generator object gensquares at 0x0000000003587B88>

调用生成器函数返回一个生成器

 1 >>> generator = gensquares(5)
 2 '''
 3 第一次调用生成器的next方法时,生成器才开始执行生成器函数(而不是构建生成器时),直到遇到yield时暂停执行(挂起),并且yield的参数将作为此次next方法的返回值;
 4 '''
 5 >>> next(generator)
 6 0
 7 >>> next(generator)
 8 1
 9 >>> next(generator)
10 '''
11 之后每次调用生成器的next方法,生成器将从上次暂停执行的位置恢复执行生成器函数,直到再次遇到yield时暂停,并且同样的,yield的参数将作为next方法的返回值;
12 '''
13 4
14 >>> next(generator)
15 9
16 #当next函数到达生成器末尾时候,会抛出StopIteration异常
17 >>> next(generator)
18 Traceback (most recent call last):
19   File "<pyshell#40>", line 1, in <module>
20     next(generator)
21 StopIteration

在生成器迭代的过程中接入另一个生成器

1 >>> def generator():  #创造一个生成器函数
2     yield 1
3     yield 2
4     yield from range(10)  #接入另一个生成器
5 >>> for i in generator():print(i,end="|")   #通过for循环遍历
6 1|2|0|1|2|3|4|5|6|7|8|9|

 send函数

send是除next外另一个恢复生成器的方法。其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。

 1 >>> def gen():
 2     for i in range(10):
 3         x = yield i
 4         print(x)        
 5 >>> x = gen()
 6 >>> next(x)
 7 0
 8 >>> x.send(44)
 9 44
10 1
11 >>> x.send(24)
12 24
13 2
14 >>> next(x)
15 None
16 3

 

 

posted on 2013-11-04 23:59  kolaman  阅读(282)  评论(0)    收藏  举报