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

 

參考文檔:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM