Python中的迭代是指按照元素的順序逐個調用的過程,迭代概念包括:迭代協議、可迭代對象和迭代器三個概念。
迭代協議是指有__next__()函數的對象會前進到下一個結果,而到達系列的末尾時,則會引發StopIteration異常。為了支持迭代協議,Python內置了兩個函數:iter()和next()函數。iter()從可迭代對象中獲得一個迭代器,迭代器含有next()函數。next()函數的作用就是調用對象的__next__()函數,從而遞進進到下一項。
在Python中,任何支持迭代協議的對象都是可迭代的。如果對象是序列類型,或者在迭代工具中一次產生一個結果,那么就是可迭代的,這就以為着,序列(字符串、元組和列表)是可迭代對象。
迭代器是Python中實現迭代協議的對象,具體指的是iter()返回的,支持next()函數的對象。
Python中的迭代工具會自動調用iter()和next()函數以實現迭代,迭代工具主要有:for循環、列表解析、in成員關系測試以及map內置函數等。
一,手動迭代
列表不是自身的迭代器,對於這樣的可迭代對象,可以調用iter()函數來啟動迭代,調用next()函數遞進到下一項:
>>> a=list(range(0,5)) >>> a is iter(a) False >>> a=iter(a) >>> next(a) 0
像for循環等迭代工具,會自動調用iter()和next()函數,以實現序列的自動迭代:
>>> for i in range(0,5): print(i,end=' ') 0 1 2 3 4
二,生成器
生產器是一個延遲產生結果的工具,在需要的時候才產生結果,而不是立即產生結果。
1,生成器函數
Python提供了yield語句以實現生成器函數,以實現在需要的時候才產生結果,而不是立即產生結果。Python的生產器函數是指:編寫為常規的def語句,但是使用yield語句,一次返回一個結果,在每個結果之間掛起和繼續的狀態。
生產器函數自動實現迭代協議,每次調用只返回一個值,下次調用時,會從其退出的地方繼續執行。
生產器函數和常規函數的不同之處在於:生產器yield一個值,而不是return一個值。yield語句掛起該函數,並向調用者發送一個值,但是,保留足夠的狀態以使得函數能夠從它離開的地方繼續執行。當繼續時,函數在上一個yield返回后繼續執行。這使得生產器函數每次調用只返回一個值,窮盡調用會產生一系列的值。
>>> def seq_int(n): for i in range(n): yield i**2 >>> for i in seq_int(5): print(i,end =' ') 0 1 4 9 16
生產器函數返回的對象就是迭代器,可以使用next()前進到下一項:
>>> func=seq_int(5) >>> iter(func) is func True >>> next(func) 0
2,生產器表達式
另外一個實現生產器的對象是生產器表達式,從語法上講,生成器表達式是在小括號中的表達式。從執行過程來講,生產器表達式不在內存中構建結果,而是返回一個生成器對象,這個對象支持迭代協議。
>>> a=(x**2 for x in range(0,5)) >>> a is iter(a) True
三,解析
解析分為列表解析,集合解析和字典解析。
- 列表解析的格式是:[ f(x) for x in seq ],對應的生成器表達式是:list( f(x) for x in seq )
- 集合解析的格式是:{ f(x) for x in seq },對應的生成器表達式是:set(f(x) for x in seq )
- 字典解析的格式是:{key:value for (key, value) in zip(keys,values)},對應的生成器表達式是:dict((x,f(x)) for x in items )
從語法上講,列表解析是在中括號中的表達式;從執行過程來講,列表解析對序列中的每一個元素執行一個操作;從執行的結果來講,列表解析產生的一個新的列表對象。
由於列表解析產生的結果是一個列表對象,包含所有的序列項,不屬於延遲產生結果的工具。
>>> a=[x**2 for x in range(0,5)] >>> isinstance(a,list) True
四,內置的迭代器函數
這一節,總結Python 3.0中內置的迭代器函數,除了range()函數之外,其余的函數都會產生迭代器對象,延遲產生結果。
1,range 迭代對象
range返回一個可迭代對象,該迭代對象根據需要產生范圍中的數字,而不是在內存中構建一個列表。如果需要一個范圍列表的話,必須使用list( range(...))來強制返回一個列表。
>>> r = range(0,5) >>> iter(r) is r False >>> list(r) [0, 1, 2, 3, 4] >>> r=iter(r) >>> next(r) 0
2,zip實現並行遍歷
zip()函數用於合並序列,按照序列中元素的位置,把序列的元素組合成元組,元組項的數量就是zip合並的序列的個數。當序列的長度不同時,zip會以最短序列的長度為准來截斷所得到的元組。
例如,zip把序列a和b合並為一個序列c,c的元素的元組(0,5),(1,6),(2,7),(3,8),(4,9)。
>>> a = range(0,5) >>> b = range(5,10) >>> c = zip(a,b) >>> iter(c) is c True >>> next(c) (0, 5) >>> list(c) [(1, 6), (2, 7), (3, 8), (4, 9)]
3,map對序列應用函數
map()函數對一個序列的各個元素應用函數,返回函數調用的結果序列。
>>> m=map(ord,'abcd') >>> iter(m) is m True >>> list(m) [97, 98, 99, 100]
4,產生偏移和元素
enumerate是Python內置的函數,作用於每一個序列項,獲取每一個序列項偏移,並把偏移和序列項組合成元組(index, item)返回。原始序列的每個元素及其索引都能得到。
enumerate()函數返回一個迭代器對象,使用next()方法會返回下一個元素:
>>> t=enumerate('abcd') >>> iter(t) is t True >>> list(t) [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
在for循環結構中,每次迭代,for循環都會自動調用next()函數以返回下一個元組(index,item):
>>> [c * i for (i,c) in enumerate('abcd')] ['', 'b', 'cc', 'ddd']
5,filter迭代器
filter()函數對一個序列的各個元素應用函數,返回結果為True的元素。
>>> f=filter(bool, ['a','','b',None]) >>> iter(f) is f True >>> list(f) ['a', 'b']
6,reduce() 函數
注意:reduce()函數並不是一個迭代器,它是functools模塊中的一個工具函數。
reduce()用於對序列的元素依次應用函數,並把函數調用的結果作為參數傳遞給函數,最終返回函數調用的結果。
>>> from functools import reduce >>> reduce((lambda x,y:x+y),range(0,5)) 10
reduce()函數執行流程等價於下面的代碼塊:
x=list(range(0,5)] res=x[0] for i in x[1:] : res+=i
參考文檔: