您好,登錄后才能下訂單哦!
本文實(shí)例講述了Python通過(guò)for循環(huán)理解迭代器和生成器。分享給大家供大家參考,具體如下:
迭代器
可迭代對(duì)象
通過(guò) for…in… 循環(huán)依次拿到數(shù)據(jù)進(jìn)行使用的過(guò)程稱為遍歷,也叫迭代。我們把可以通過(guò) for…in… 語(yǔ)句迭代讀取數(shù)據(jù)的對(duì)象稱之為可迭代對(duì)象。
- 通過(guò)
isinstance()
可以判斷一個(gè)對(duì)象是否可以迭代
# 判斷列表 print(isinstance([], Iterable)
打印結(jié)果為 True 即為可迭代對(duì)象。
- 自定義一個(gè)能容納數(shù)據(jù)的類,測(cè)試該類的可迭代性
import collections class MyClassmate(object): def __init__(self): self.names = [] def add(self, name): self.names.append(name) # 創(chuàng)建 MyClassmate對(duì)象 my_classmate = MyClassmate() my_classmate.add("小王") my_classmate.add("小李") my_classmate.add("小張") # 判斷MyClassmate是否為可迭代對(duì)象 print("是否為可迭代對(duì)象:",isinstance(my_classmate, collections.Iterable)) # 迭代數(shù)據(jù) for temp in my_classmate: print(temp)
運(yùn)行結(jié)果:
是否為可迭代對(duì)象: False
Traceback (most recent call last):
for temp in my_classmate:
TypeError: 'MyClassmate' object is not iterable
封裝一個(gè)可以存放多條數(shù)據(jù)的類型是不可迭代的
何為可迭代對(duì)象
__iter__
方法向我們提供一個(gè)迭代器,在迭代一個(gè)可迭代對(duì)象的時(shí)候,實(shí)際上就是先獲取該對(duì)象提供的一個(gè)迭代器,然后通過(guò)這個(gè)迭代器來(lái)依次獲取對(duì)象中的每一個(gè)數(shù)據(jù).1.可迭代對(duì)象的本質(zhì)就是提供一個(gè)這樣的中間"人"即迭代器幫助我們對(duì)其進(jìn)行迭代遍歷使用
2.可迭代對(duì)象是一個(gè)具備了
__iter__
方法的對(duì)象,通過(guò)__iter__
方法獲取可迭代對(duì)象的迭代器
from collections import Iterable class MyClassmate(object): def __init__(self): self.names = [] def add(self, name): self.names.append(item) def __iter__(self): """空實(shí)現(xiàn)該方法""" return None # 創(chuàng)建 MyClassmate對(duì)象 my_classmate = MyClassmate() my_classmate.add("小王") my_classmate.add("小李") my_classmate.add("小張") # 判斷MyClassmate是否為可迭代對(duì)象 print(isinstance(my_classmate, Iterable))
運(yùn)行結(jié)果:
是否為可迭代對(duì)象: True
這回測(cè)試發(fā)現(xiàn)添加了__iter__
方法的my_classmate對(duì)象已經(jīng)是一個(gè)可迭代對(duì)象了。
iter() 函數(shù)與 next() 函數(shù)
list、tuple 等都是可迭代對(duì)象,我們可以通過(guò) iter() 函數(shù)獲取這些可迭代對(duì)象的迭代器。然后我們可以對(duì)獲取到的迭代器不斷使用
next()
函數(shù)來(lái)獲取下一條數(shù)據(jù)。
li = [11, 22, 33, 44, 55] # 通過(guò)iter() 取得可迭代對(duì)象的迭代器 iterator = iter(li) # 通過(guò)next()函數(shù)取得iterator迭代器指向的下一個(gè)值 print(next(iterator)) print(next(iterator)) print(next(iterator)) print(next(iterator)) print(next(iterator)) print(next(iterator))
1.
iter(iterable)
函數(shù)是把可迭代對(duì)象的迭代器取出來(lái),內(nèi)部是調(diào)用可迭代對(duì)象的__iter__
方法,來(lái)取得迭代器的2.
next(iterator)
函數(shù)是通過(guò)迭代器取得下一個(gè)位置的值,內(nèi)部是調(diào)用迭代器對(duì)象的__next__
方法,來(lái)取得下一個(gè)位置的值
注意: 當(dāng)我們已經(jīng)迭代完最后一個(gè)數(shù)據(jù)之后,再次調(diào)用 next()
函數(shù)會(huì)拋出 StopIteration 的異常,來(lái)告訴我們所有數(shù)據(jù)都已迭代完成,不用再執(zhí)行 next()
函數(shù)了。
迭代器
我們要想構(gòu)造一個(gè)迭代器,就要實(shí)現(xiàn)它的
__next__
方法。但這還不夠,python 要求迭代器本身也是可迭代的,所以我們還要為迭代器實(shí)現(xiàn)__iter__
方法,而__iter__
方法要返回一個(gè)迭代器,迭代器自身正是一個(gè)迭代器,所以迭代器的__iter__
方法返回自身即可。一個(gè)實(shí)現(xiàn)了
__iter__
方法和__next__
方法的對(duì)象,就是迭代器,迭代器同時(shí)也是一個(gè)可迭代對(duì)象.
import collections class MyClassmate(object): def __init__(self): # 聲明一個(gè)列表 self.names = [] # 記錄迭代器迭代的位置, 默認(rèn)是0 ,即從起始位置開始 self.current = 0 def add(self, name): self.names.append(name) def __iter__(self): """通過(guò)該方法取得迭代器對(duì)象""" return self def __next__(self): """取得下一個(gè)迭代的值""" if self.current < len(self.names): name = self.names[self.current] self.current += 1 return name else: raise StopIteration # 創(chuàng)建MyClassmate實(shí)例 my_classmate = MyClassmate() my_classmate.add("小王") my_classmate.add("小李") my_classmate.add("小張") # 測(cè)試MyList是不是可迭代對(duì)象 print(isinstance(my_classmate, collections.Iterable)) # 遍歷數(shù)據(jù) for name in my_classmate: print(name)
for…in… 循環(huán)的本質(zhì)
for item in Iterable 循環(huán)的本質(zhì)就是先通過(guò)iter()
函數(shù)獲取可迭代對(duì)象 Iterable 的迭代器,然后對(duì)獲取到的迭代器不斷調(diào)用 next() 方法來(lái)獲取下一個(gè)值并將其賦值給 item,當(dāng)遇到 StopIteration 的異常后循環(huán)結(jié)束 (for…in..會(huì)自動(dòng)處理 StopIteration 異常)。
生成器
生成器
生成器是一種特殊的迭代器,它比迭代器更優(yōu)雅
創(chuàng)建生成器的方法
1.將列表生成式的 [] 改成 ()
# 參考列表生成式 L=[x*2 for x in range(6)] print(L) # 把[] 改為() :就是一個(gè)簡(jiǎn)單的列表生成器 G=(x*2 for x in range(6)) # 輸出的是生成器對(duì)象 print(G) print("通過(guò)next()函數(shù)取得下一個(gè)值") print(next(G)) print(next(G)) print(next(G)) print(next(G)) print(next(G)) print(next(G)) # 創(chuàng)建一個(gè)簡(jiǎn)單生成器,通過(guò) for來(lái)遍歷 G=(x*2 for x in range(6)) print("通過(guò)for 迭代的結(jié)果:") for num in G: print(num)
運(yùn)行結(jié)果:
[0, 2, 4, 6, 8, 10]
<generator object <genexpr> at 0x7ff7f8bbd5c8>
通過(guò)next()函數(shù)取得下一個(gè)值
0
2
4
6
8
10
通過(guò)for 迭代的結(jié)果:
0
2
4
6
8
10
2.通過(guò)關(guān)鍵字 yield 實(shí)現(xiàn)生成器
def fib(n): current_index = 0 num1, num2 = 0, 1 while current_index < n: # print(num1) # 打印斐波那契數(shù)列 """ 1. 假如函數(shù)中有yield,則不再是函數(shù),而是生成器 2. yield 會(huì)產(chǎn)生一個(gè)斷點(diǎn) 3. 假如yield后面緊接著一個(gè)數(shù)據(jù),就會(huì)把數(shù)據(jù)返回, 作為next()函數(shù)或者for ...in...迭代出的下一個(gè)值 """ yield num1 num1, num2 = num2, num1 + num2 current_index += 1 if __name__ == '__main__': # 假如函數(shù)中有yield,則不再是函數(shù),而是一個(gè)生成器 gen = fib(5) # 生成器是一種特殊的迭代器 for num in gen: print(num) # 也可以用 next() 函數(shù)取下一個(gè)值
在使用生成器實(shí)現(xiàn)的方式中,我們將原本在迭代器__next__
方法中實(shí)現(xiàn)的基本邏輯放到一個(gè)函數(shù)中來(lái)實(shí)現(xiàn),但是將打印輸出方式換成 yield,此時(shí)新定義的函數(shù)便不再是函數(shù),而是一個(gè)生成器了。簡(jiǎn)單來(lái)說(shuō):只要在函數(shù)中有 yield 關(guān)鍵字,就稱為生成器。
此時(shí)按照調(diào)用函數(shù)的方式( 案例中為 gen = fib(5)
)使用生成器就不再是執(zhí)行函數(shù)體了,而是會(huì)返回一個(gè)生成器對(duì)象( 案例中為 gen ),然后就可以按照使用迭代器的方式來(lái)使用生成器了。
使用 send()
喚醒
def gen(): i = 0 while i < 5: temp = yield i print(temp) i += 1 if __name__ == '__main__': # 取得生成器對(duì)象 obj = gen() # 使用next()喚醒生成器 print(next(obj)) print(next(obj)) # 使用send喚醒生成器 ,在喚醒的同時(shí)向斷點(diǎn)處傳入一個(gè)附加數(shù)據(jù) print(obj.send("haha")) # 使用next()喚醒生成器 print(next(obj)) # 使用send喚醒生成器 ,在喚醒的同時(shí)向斷點(diǎn)處傳入一個(gè)附加數(shù)據(jù) print(obj.send("python"))
運(yùn)行結(jié)果:
0
None
1
haha
2
None
3
python
我們除了可以使用 next() 函數(shù)來(lái)喚醒生成器繼續(xù)執(zhí)行外,還可以使用 send() 函數(shù)來(lái)喚醒執(zhí)行。使用 send() 函數(shù)的一個(gè)好處是可以在喚醒的同時(shí)向斷點(diǎn)處傳入一個(gè)附加數(shù)據(jù)。
總結(jié)
1. 假如函數(shù)中有 yield,則不再是函數(shù),而是生成器
2. yield 會(huì)產(chǎn)生一個(gè)斷點(diǎn),暫停函數(shù),保存狀態(tài)
3. 假如yield后面緊接著一個(gè)數(shù)據(jù),就會(huì)把數(shù)據(jù)返回,作為 next()
函數(shù)或者 for …in… 迭代出的下一個(gè)值
4. 可以通過(guò) next()
喚醒生成器,讓生成器從斷點(diǎn)處繼續(xù)執(zhí)行
send與next喚醒生成器不同:
1. send 與next都可以喚醒生成器,但send(value)可以傳值給生成器的斷點(diǎn)處
2. 使用:
next(generator) generator.send("你好")
3. generator.send(None)
等價(jià)于next(generator)
4. 注意: 第一次喚醒生成器時(shí),假如使用 send,則只能傳 None,因?yàn)閯傞_始執(zhí)行生成器時(shí),是沒(méi)有斷點(diǎn)的
- 解析
temp = yield num generator.send("你好")
temp = yield num 為賦值語(yǔ)句,當(dāng)看到等號(hào)時(shí), 一定是等號(hào)左邊先運(yùn)行完,再賦值給等號(hào)右邊
而程序運(yùn)行到 yield num 時(shí),會(huì)先返回一個(gè)值,也就是此時(shí)的 num ,然后將 send()
里的參數(shù)傳給 yield num
,進(jìn)而賦值給 temp
更多關(guān)于Python相關(guān)內(nèi)容可查看本站專題:《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python Socket編程技巧總結(jié)》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》及《Python入門與進(jìn)階經(jīng)典教程》
希望本文所述對(duì)大家Python程序設(shè)計(jì)有所幫助。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。