1 Iterable
我們一般稱Iterable
為可迭代對象
雁佳。Python 中任意的對象,只要它定義了可以返回一個(gè)迭代器的__iter__
方法同云,或者定義了可以支持下標(biāo)索引的__getitem__
方法糖权,那么它就是一個(gè)可迭代對象。我們常用到的集合數(shù)據(jù)類型都是 Iterable炸站。例如列表(list)星澳、元組(tuple)、字典(dict)旱易、集合(set)禁偎、字符串(str)等。
我定義了一個(gè)列表 numlist阀坏,打印出該列表的方法如暖。
numlist = [1, 2, 3]
print(numlist)
print(numlist.__iter__) # 調(diào)用__iter__方法
print(numlist.__getitem__) # 調(diào)用__getitem__方法
運(yùn)行結(jié)果如下:
根據(jù)運(yùn)行結(jié)果,我們可知列表就是個(gè)可迭代對象忌堂。Python 的collections
庫有個(gè)isinstance()
函數(shù)盒至。可以用來判斷一個(gè)對象是否是 Iterable 對象浸船。
from collections import Iterable
isinstance({}, Iterable)
isinstance((), Iterable)
isinstance(999, Iterable)
運(yùn)行結(jié)果為:
如果我們每次都要使用這個(gè)函數(shù)來判斷一個(gè)對象是否為可迭代對象妄迁,這樣操作有點(diǎn)麻煩寝蹈。有沒有快速判定的方法呢李命?答案是肯定的◇锢希可以直接使用 for 循環(huán)進(jìn)行遍歷的對象就是可迭代對象封字。
除此之外,generator(生成器)
和帶 yield 的 generator function
也是可迭代的對象耍鬓。
2 Iterator
Iterator
是迭代器的意思阔籽。任意對象,只要定義了next()
(Python 2 版本)或者__next__()
(Python 3 版本) 方法牲蜀,那么它就是一個(gè)迭代器笆制。迭代器中還有另一個(gè)函數(shù)__iter__()
,它和 next() 方法形成迭代器協(xié)議涣达。
iter()
返回主要是返回迭代器對象本身在辆,即return self
证薇。如果你自己定義個(gè)迭代器,實(shí)現(xiàn)該函數(shù)就能使用for ... in ...
語句遍歷了匆篓。next()
獲取容器中的下一個(gè)元素浑度,當(dāng)沒有可訪問元素后,就拋出StopIteration
異常鸦概。
遍歷迭代器有兩個(gè)方式箩张。一種是使用 next() 函數(shù);另一種則是使用 for each 循環(huán)窗市,本質(zhì)上就是通過不斷調(diào)用 next() 函數(shù)實(shí)現(xiàn)的先慷。
from collections import Iterator
numlist = [1, 2, 3]
# 將數(shù)組轉(zhuǎn)化為迭代器
ite1 = iter(numlist)
print(ite1)
for i in ite1:
print(i)
print("=========")
ite2 = iter(numlist)
while True:
try:
num = ite2.__next__()
print(num)
except StopIteration:
break
值得注意的是一個(gè) Iterator 只能遍歷一次。
3 generator
generator 翻譯成中文是生成器咨察。生成器也是一種特殊迭代器熟掂。它其實(shí)是生成器函數(shù)返回生成器的迭代,“生成器的迭代器”這個(gè)術(shù)語通常被稱作”生成器”扎拣。yield 是生成器實(shí)現(xiàn)__next__()
方法的關(guān)鍵赴肚。它作為生成器執(zhí)行的暫停恢復(fù)點(diǎn)二蓝,可以對 yield 表達(dá)式進(jìn)行賦值誉券,也可以將 yield 表達(dá)式的值返回。任何包含 yield 語句的函數(shù)被稱為生成器刊愚。
yield是一個(gè)語法糖踊跟,內(nèi)部實(shí)現(xiàn)支持了迭代器協(xié)議,同時(shí)yield內(nèi)部是一個(gè)狀態(tài)機(jī)鸥诽,維護(hù)著掛起和繼續(xù)的狀態(tài)商玫。
個(gè)人認(rèn)為,生成器算是 Python 非常棒的特性牡借。它的出現(xiàn)能幫助大大節(jié)省些內(nèi)存空間拳昌。假如我們要生成從 1 到 10 這 10 個(gè)數(shù)字,采用列表的方式定義钠龙,會占用 10 個(gè)地址空間炬藤。采用生成器,只會占用一個(gè)地址空間碴里。因?yàn)樯善鞑]有把所有的值存在內(nèi)存中沈矿,而是在運(yùn)行時(shí)生成值。所以生成器只能訪問一次咬腋。
創(chuàng)建一個(gè)從包含 1 到 10 的生成器的例子羹膳。
gen = (i for i in range(10))
print(gen)
for i in gen:
print(i)
運(yùn)行結(jié)果如下:
帶有 yield 關(guān)鍵字 的例子。重點(diǎn)關(guān)注運(yùn)行結(jié)果,這能讓你對 yield 有更深的認(rèn)識拱绑。
def testYield(n):
for i in range(n):
print("當(dāng)前值: ", i)
yield doubeNumber(i)
print("第 ", i, " 次運(yùn)行")
print("testYield 運(yùn)行結(jié)束")
def doubeNumber(i):
return i*2
if __name__ == '__main__':
for i in testYield(3):
print(i, "===", i)
運(yùn)行結(jié)果如下:
上篇閱讀:Python 繪圖葛超,我只用 Matplotlib(二)
推薦閱讀:爬蟲系列的總結(jié)