1. 程式人生 > >Python 語言學習 第六篇:迭代和解析

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