目錄:
一、迭代器
二、生成器
一、迭代器
我們提一下先提迭代的概念:迭代即為循環(huán)遍歷,任何遍歷的過程都是可以稱作迭代。Python中序列、集合、字典、文件和生成器等都是可迭代的,任何可迭代對象都可以作用于for循環(huán)。
首先我們來借助最基本的兩個內(nèi)置函數(shù)iter() 和 next()來完成一個簡單的迭代器。
a=range(3)
it=iter(a) # 創(chuàng)建迭代器對象
while 1:
print (next(it)) #輸出迭代器的下一個元素,迭代器對象從第一個元素開始訪問,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會后退。
#輸出
0
1
2
Traceback (most recent call last):
print (next(it))
StopIteration
我們可以看到觸發(fā)了StopIteration異常,StopIteration 異常用于標(biāo)識迭代的完成,防止出現(xiàn)無限循環(huán)的情況,所以我們做如下改寫:
import sys
a=range(3)
it=iter(a) # 創(chuàng)建迭代器對象
while 1:
try:
print (next(it)) #輸出迭代器的下一個元素,迭代器對象從第一個元素開始訪問,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會后退。
except StopIteration: #我們設(shè)置在完成循環(huán)次后捕獲 StopIteration 異常來結(jié)束迭代。
sys.exit()
#輸出
0
1
2
但,for循環(huán)卻自帶異常處理機制:
a=range(3)
it=iter(a) # 創(chuàng)建迭代器對象
for i in a:
print (next(it))
#輸出
0
1
2
類中迭代器的使用
然后我們來拓展一下關(guān)于類中的迭代器,之前大家應(yīng)該也已經(jīng)留意到了,類中是內(nèi)置了迭代器的專有方法的。
class Numbers:
def __init__(self,n): #構(gòu)造函數(shù),獲取參數(shù)范圍,即打印0到幾
self.n=n
def __iter__(self): #實例化對象的迭代器創(chuàng)建方法
self.a=0
return self
def __next__(self): #返回迭代器對象下一個元素的方法
if self.a <=self.n:
res=self.a
self.a+=1
return res
else:
raise StopIteration #raise用以引發(fā)異常。一旦執(zhí)行了raise語句,raise后面的語句將不能執(zhí)行
num=Numbers(3) #實例化對象num
it=iter(num) #創(chuàng)建實例num的迭代器對象it
print(next(it)) #輸出迭代器對象it的下一個元素
print(next(it))
print(next(it))
print(next(it))
#輸出
0
1
2
3
當(dāng)然,我們最后的輸出完全可以使用for循環(huán)將迭代器中的內(nèi)容讀出來,輸出相同。
# print(next(it)) #輸出迭代器對象it的下一個元素
# print(next(it))
# print(next(it))
# print(next(it))
for i in it:
print(i)
或者使用while循環(huán),不過依然要添加異常處理:
while 1:
try:
print(next(it))
except StopIteration: #使用try-except語句捕捉異常
pass #啥也不想干,占個位
二、生成器
而生成器是一個簡單的方式來完成迭代,生成器是一個返回迭代器的函數(shù),只能用于迭代操作,更簡單點理解生成器就是一個迭代器。
覺得上面的概念太抽象?我們借助實例來解釋~幾乎所有相關(guān)教程都在扯著名的斐波那契數(shù)列,我們就不!
說起生成器的創(chuàng)建,常用兩種方法,一種是改寫列表生成式,一種是使用yield。
列表生成式
列表生成式即List Comprehensions,是Python內(nèi)置的非常簡單卻強大的可以用來創(chuàng)建list的生成式,其實我們之前就有在使用了。
a=[x for x in range(10)]
print(a)
#輸出
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
顧名思義,它生成了一個列表,那么如何改寫為生成器呢?
a=(x for x in range(10))
print(type(a))
#輸出
<class 'generator'>
我們可以看到,當(dāng)前類型已經(jīng)變?yōu)?generator',即生成器類型。改寫方法就是將[ ]替換為( )。
接下來我們嘗試使用一下:
a=(x for x in range(10))
while 1:
try:
print(next(a))
except:
pass
#輸出
0
1
2
3
4
5
6
7
8
9
yield
在python中,任何使用了 yield 的函數(shù)都被稱為生成器(generator)或生成器函數(shù)。
def numbers(n): #創(chuàng)建生成器函數(shù),這已經(jīng)不是一個普通函數(shù)啦
for i in range(n):
yield i #在調(diào)用生成器運行的過程中,每次遇到 yield 時函數(shù)會暫停并保存當(dāng)前所有的運行信息,返回 yield 的值, 并在下一次執(zhí)行 next() 方法時從當(dāng)前位置繼續(xù)運行。
num=numbers(3) #調(diào)用生成器函數(shù),返回的是一個迭代器對象,即num。
for i in num: #上個例子用的while,這次我們用for
print(i)
#輸出
0
1
2
這里往上翻一下,你會發(fā)現(xiàn)它與類中迭代器的使用中的例子功能是一致的,但那里用了近20行代碼,然而生成器卻只用了三行代碼,這就是我們?yōu)槭裁凑f生成器是使用簡單的方式進行迭代。
說到底,生成器就是一種特殊的迭代器,這也就是為什么這一章節(jié)題目如此簡單:《迭代》。