Python 語言學習 第六篇:迭代和解析
Python 語言學習 第六篇:迭代和解析
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