16.生成器-迭代器
? ? 可回圈迭代的物件稱為可迭代物件,迭代器和生成器函式是可迭代物件,在Python中提供了定義迭代器和生成器的協議和方法,
16.1 迭代和可迭代物件
16.1.1 可迭代物件、迭代器和可迭代協議
1.可迭代物件
? ? 在Python中,實作了__iter__()的物件是可迭代物件(Iterable),使用內置函式iter(obj),可以呼叫可迭代物件obj的__iter__()方法,并回傳一個迭代器(iterator),如字串、元組、串列等都是可迭代物件,生成器函式和生成器運算式也是可迭代物件,判斷一個物件是否為可迭代物件,可使用以下方式:
>>> from collections import abc
>>> isinstance((1,2,3,4),(abc.Iterable,))
True
>>> isinstance("abcdef",(abc.Iterable,))
True
>>> isinstance(123,(abc.Iterable,))
False
>>> isinstance("123",(abc.Iterable,))
True
>>> isinstance({1,2,3},(abc.Iterable,))
True
>>> isinstance({"a":1,"b":2},(abc.Iterable,))
True
2.迭代器
? ? 實作了__next__的物件是迭代器,可以使用內置函式next(),呼叫迭代器的__next__()方法,依次回傳下一個值,如果沒有值,則拋出例外StopIteration,使用迭代器可以實作物件的迭代回圈,讓程式更加通用,高效,示例如下所示:
>>> from collections import abc
>>> tempA=(i**2 for i in range(10))
>>> isinstance(tempA,(abc.Iterable,))
True
>>> tempB={i*2 for i in range(10)}
>>> isinstance(tempB,(abc.Iterable,))
True
3.迭代器協議
? ? 迭代器物件必須實作兩個方法__iter__()和__next__(),這兩個方法被稱為迭代器協議,__iter__()用于回傳物件本身,以方便使用回圈陳述句(for)進行迭代,__next__()用于回傳下一元素,示例如下所示:
>>> from collections import abc
>>> tempA=(i**2 for i in range(10))
>>> help(tempA)
| __iter__(self, /)
| Implement iter(self).
|
| __next__(self, /)
| Implement next(self).
16.1.2 可迭代物件的迭代:iter和next函式
? ? 使用內置函式iter(iterable),可以回傳可迭代物件iterable的迭代器;使用內置函式next()函式,可依次回傳迭代器物件的下一個值,如果沒有值,則拋出例外StopIteration,示例如下所示:
>>> temp=[1,2,3,4] # 可迭代物件
>>> v=iter(temp) # 通過內置函式iter獲取iterator
>>> next(v) # 通過內置函式next獲取值
1
>>> next(v)
2
>>> next(v)
3
>>> next(v)
4
>>> next(v) # 當沒有值,則拋出例外StopIteration
Traceback (most recent call last):
File "<input>", line 1, in <module>
StopIteration
? ? 除了使用next函式個,也可以使用while回圈可迭代物件,如下所示:
temp=[1,2,3,4]
v=iter(temp)
while True:
try:
value=https://www.cnblogs.com/surpassme/p/next(v)
except StopIteration:
break
print(value,end=" ")
運行結果如下所示:
1 2 3 4
16.1.3 可迭代物件的迭代:for陳述句
? ? 實際專案中,通常會使用for陳述句實作可迭代物件的迭代,Python中的for回圈實作了自動迭代可迭代物件的功能,如下所示:
>>> temp=[1,2,3,4]
>>> for item in temp:
... print(item,end=" ")
...
1 2 3 4
>>> for item in "abcdef":
... print(item,end="-")
...
a-b-c-d-e-f-
16.2 自定義可迭代物件和迭代器
? ? 創建一個類,定義__iter__()和__next__()兩個方法,實體化該類的物件,即為可迭代物件,也是迭代器,示例如下所示:
class Fibonacci:
def __init__(self):
self._first=0
self._second=1
def __next__(self):
# f(n)=f(n-1)+f(n-2)
self._first,self._second=self._second,self._first+self._second
return self._first
def __iter__(self):
return self
fib=Fibonacci()
for f in fib:
if f<100:
print(f,end=" ")
else:
break
輸出結果如下所示:
1 1 2 3 5 8 13 21 34 55 89
16.3 生成器函式
? ? 在函式定義中,如果使用關鍵字yield陳述句代替return回傳一個值,則表示定義了一個生成器函式(generator),生成器函式使用yield陳述句回傳一個值,然后保存當前函式的整個執行狀態,等待下一次呼叫,生成器函式是一個迭代器,是可迭代物件,示例如下所示:
>>> def generatorSample(n):
... for i in range(n):
... yield i**2
...
>>> f=generatorSample(5)
>>> f
<generator object generatorSample at 0x00000260CE70E7C8>
>>> item=iter(f) # 通過內置函式iter獲得iterator
>>> next(item) # 通過內置函式next獲取一個值
0
>>> next(item) # 通過內置函式next獲取一個值
1
>>> for i in f:
... print(i,end=" ")
...
4 9 16 # 使用for回圈獲取剩下的值
? ? 下面我們再用生成器生成Fibonacci數列,示例代碼如下所示:
def Fibonacci():
first,second=0,1
while True:
first,second=second,first+second
yield first
for f in Fibonacci():
if f<100:
print(f,end=" ")
else:
break
輸出結果如下所示:
1 1 2 3 5 8 13 21 34 55 89
16.4 反向迭代器:reversed迭代器
? ? 使用內置函式reversed(),可以實作一個反向迭代器,如果一個可迭代物件實作了__reversed__()方法,則可使用reversed()函式獲得其反向可迭代物件,示例如下所示:
>>> reversed([1,2,3,4,5])
<list_reverseiterator object at 0x00000260CF0D8908>
>>> for item in reversed([1,2,3,4,5]):
... print(item,end=" ")
...
5 4 3 2 1
? ? 實作一個可反向迭代的迭代器示例:
class CountSample:
def __init__(self,startIndex):
self._startIndex=startIndex
# 正向迭代
def __iter__(self):
n=self._startIndex
while n > 0:
yield n
n-=1
# 反向迭代
def __reversed__(self):
n=1
while n<= self._startIndex:
yield n
n+=1
if __name__ == '__main__':
obj=CountSample(10)
print("正向迭代")
for item in obj :
print(item,end=" ")
print("\n反向迭代")
for item in reversed(obj):
print(item,end=" ")
輸出結果如下所示:
正向迭代
10 9 8 7 6 5 4 3 2 1
反向迭代
1 2 3 4 5 6 7 8 9 10
16.5 生成器運算式
? ? 使用生成器運算式,可以簡便快捷回傳一個生成器,生成器運算式的語法和前面所講的串列決議式基本一樣,區別在于生成器運算式使用()代表[],基本使用格式如下所示:
( expr for iterVar in iterable )
( expr for iterVar in iterable if condition)
? ? 運算式expr使用每次迭代內容iterVar,計算生成一個串列,如果在指定條件運算式condition,則只有滿足條件的iterable元素參與迭代,如下所示:
>>> (i**2 for i in range(10))
<generator object <genexpr> at 0x00000260CF0B0EC8> # 輸出表明是一個生成器
>>> for item in (i**2 for i in range(10)):
... print(item,end=" ")
...
0 1 4 9 16 25 36 49 64 81
>>> for item in (i**2 for i in range(10) if i%2==0):
... print(item,end=" ")
0 4 16 36 64
16.5 小結
- 1.可迭代物件(iterable):可回圈迭代的物件稱為可迭代物件
- 2.迭代器(iterator): 實作了__iter__()和__next__()的物件,__iter__回傳迭代器自身,__next__回傳迭代器中的下一個值,如果沒有元素,則拋出StopIteration例外
- 3.生成器(generator):一種特殊的迭代器,使用關鍵字yield定義,生成器一定是迭代器,反之則不成立,
- 4.迭代物件與迭代器的示意圖如下所示:

本文地址:https://www.cnblogs.com/surpassme/p/13028211.html
本文同步在微信訂閱號上發布,如各位小伙伴們喜歡我的文章,也可以關注我的微信訂閱號:woaitest,或掃描下面的二維碼添加關注:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/140869.html
標籤:Python
