Python-迭代器相關(guān)概念

各概念關(guān)系圖

一些基本概念


1 容器

可以詢問(wèn)某個(gè)元素是否包含其中,如list,set,tuples,dict等都是容器

2 迭代器(iterator)


1)迭代器是一個(gè)帶狀態(tài)的對(duì)象,任何實(shí)現(xiàn)了iter和next__方法的對(duì)象都是迭代器(python2:任何實(shí)現(xiàn)next()方法的對(duì)象都是迭代器)。
2)其中iter返回迭代器本身,next返回容器中的下一個(gè)值。如果容器中沒(méi)有更多元素了,則拋出Stopiteration異常。

因此,可以把迭代器理解成一個(gè)帶有流水線的工程,我們每次詢問(wèn)他時(shí),他就給我們返回下一個(gè)值。迭代器會(huì)把所有的值都存儲(chǔ)在內(nèi)存中。

2.1 next()

next()函數(shù) 用來(lái)返回文件的下一行/下一個(gè)值,直到促發(fā)STopIteration。
《Python File next() 方法》

2.2 iter()

用處:把可迭代對(duì)象變?yōu)榈鳌?/p>

3 可迭代對(duì)象(iterable)


凡是可以返回一個(gè)迭代器的對(duì)象都可以稱之為可迭代對(duì)象(除了上面提到的list,tuples,dict等容器外,還有很多其他對(duì)象也是可迭代對(duì)象。比如,打開(kāi)狀態(tài)的files.
我的理解是所有可以使用 for .. in .. 語(yǔ)法的對(duì)象都可以叫做一個(gè)迭代對(duì)象。
但是迭代器把所有的值都存儲(chǔ)到了內(nèi)存中,如果有大量數(shù)據(jù)的話,這個(gè)方式就會(huì)占用大量?jī)?nèi)存。

注:很多容器都是可迭代對(duì)象,但并不是所有容器都是可迭代對(duì)象.

下面的例子可以幫助更好的理解可迭代對(duì)象。

 >>> x = [1, 2, 3]
>>> y = iter(x)
>>> z = iter(x)
>>> next(y)
1
>>> next(y)
2
>>> next(z)
1
>>> type(x)
<class 'list'>
>>> type(y)
<class 'list_iterator> 

上題中,x就是一個(gè)可迭代對(duì)象。可迭代對(duì)象和容器一樣是一種通俗的叫法,并不是指某種具體的數(shù)據(jù)類(lèi)型,列表是可迭代對(duì)象,字典是可迭代對(duì)象,集合也是可迭代對(duì)象。

我們用 liter() 函數(shù)可以把可迭代對(duì)象變?yōu)榈鲗?duì)象。

上面代碼中,y和z是兩個(gè)獨(dú)立的迭代器。迭代器內(nèi)部持有一個(gè)狀態(tài),該狀態(tài)用于記錄當(dāng)前迭代所在的位置,以方便下次迭代的時(shí)候獲取正確的元素。迭代器有一種具體的迭代器類(lèi)型,比如list_iterator,set_iterator??傻鷮?duì)象實(shí)現(xiàn)了iter方法,該方法返回一個(gè)迭代器對(duì)象。
當(dāng)運(yùn)行以下代碼時(shí):

x = [1, 2, 3]
for elemments in x:
    ...

實(shí)際執(zhí)行情況是:

迭代對(duì)象--->迭代器

4 生成器(generator)


生成器其實(shí)是一種特殊的迭代器。它和一般迭代器不同的地方在于,我們 只可以讀取它一次,因?yàn)樗⒉话阉械闹捣旁趦?nèi)存中,它是實(shí)時(shí)地生成數(shù)據(jù):

>>> mygenerator = (x*x for x in range(3))  #range后面會(huì)介紹
>>> for i in mygenerator :
...    print(i)

結(jié)果:
0
1
4

生成器只能讀取一次是什么意思?舉個(gè)例子:

# -*- coding: UTF-8 -*-
def mygenerator(n):   #建一個(gè)生成器
     for x in range(n):
         yield int(x)


y = mygenerator(5) 
z = sum(y) # 使用一次生成器。遍歷mygenerator中所有數(shù),并相加

for i in y:    #第二次使用生成器
    print(i)   #print不會(huì)有任何結(jié)果,因?yàn)橐呀?jīng)使用過(guò)一次生成器。

本節(jié)中其他相關(guān)函數(shù)的意思:

range()
range(y,x,z); y表示起始范圍,x表示終止范圍,z表示間隔值
1.range(x) 表示0-x范圍內(nèi)的數(shù)(不包含x)
2.range(y,x)表示y-x范圍內(nèi)的數(shù)(不包含x)
3.range(y,x,z)表示y-x范圍內(nèi)(不包含x),間隔為z的數(shù).

更具體一點(diǎn)的說(shuō)明:
《詳細(xì)記錄python的range()函數(shù)用法》

和range()函數(shù)相似的,還有個(gè)xrange()函數(shù),具體見(jiàn)下面說(shuō)明:

xrange()
參數(shù)與range()函數(shù)一樣,不一樣的地方在于,xrange()生成的不是一個(gè)數(shù)組,而是一個(gè)生成器。

xrange() 和 range()的區(qū)別可以參見(jiàn)以下詳細(xì)資料:
《Python的range和xrange》

舉例:

>>> range(5) 
[0, 1, 2, 3, 4] 
>>> xrange(5)
xrange(5)
>>> list(xrange(5))
[0, 1, 2, 3, 4]

由上面可以,range()會(huì)直接生成列表,而xrange()會(huì)生成一個(gè)生成器。因此,range相比于xrange會(huì)預(yù)先占用很多資源。

比如,如果是range(1000),那個(gè)range會(huì)直接生成0-1000的列表,預(yù)先占用內(nèi)存;但是xrange只會(huì)生成xrange生成器,需要用到具體函數(shù)時(shí),再占用相應(yīng)的內(nèi)存。所以xrange做循環(huán)的性能比range好,尤其是返回很大的時(shí)候,盡量用xrange。

生成器與迭代器的代碼區(qū)分

例子:

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist :
...    print(i)

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator :
...    print(i)

前一個(gè)[ ] 迭代器,后一個(gè)()生成器。

5 yield 關(guān)鍵詞


yield 是一個(gè)類(lèi)似 return 的關(guān)鍵字,只是這個(gè)函數(shù)返回的是個(gè)生成器。

>>> def createGenerator() :
...    mylist = range(3)
...    for i in mylist :
...        yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4

當(dāng)我們用print(mygenerator)調(diào)用createGenerator()這個(gè)函數(shù)的時(shí)候,函數(shù)內(nèi)部的代碼并不立馬執(zhí)行 ,這個(gè)函數(shù)只是返回一個(gè)生成器對(duì)象。

只有當(dāng)我們使用for進(jìn)行迭代的時(shí)候,函數(shù)內(nèi)代碼才會(huì)執(zhí)行。

第一次迭代時(shí),函數(shù)從開(kāi)始一直執(zhí)行到 yield這個(gè) 關(guān)鍵字,然后返回 yield 后的值(即ii)作為第一次迭代的返回值(即將0作為返回值).每次執(zhí)行這個(gè)函數(shù),都會(huì)繼續(xù)執(zhí)行你在函數(shù)內(nèi)部定義的那個(gè)循環(huán)的下一次,再返回那個(gè)值。例如,第二次執(zhí)行,迭代返回值為11=1。當(dāng)我們不斷調(diào)用,這個(gè)過(guò)程會(huì)一直持續(xù),直到?jīng)]有可以返回的值為止。
生成器下一次迭代是從上一次結(jié)束的地方開(kāi)始,而不會(huì)從頭開(kāi)始。比如第一次迭代后。第二次迭代是從i=1開(kāi)始,而不是從i=0開(kāi)始。

如果生成器內(nèi)部沒(méi)有定義 yield 關(guān)鍵字,那么這個(gè)生成器被認(rèn)為成空的。這種情況可能因?yàn)槭茄h(huán)進(jìn)行沒(méi)了,或者是沒(méi)有滿足 if/else 條件。

迭代器有關(guān)工具:itertools

itertools 是一個(gè)模塊,集合了眾多的迭代函數(shù),功能非常強(qiáng)大,具體可以見(jiàn)以下內(nèi)容

《PYTHON-進(jìn)階-ITERTOOLS模塊小結(jié)》


參考資料

1《(譯)Python關(guān)鍵字yield的解釋》
2.《完全理解 Python 迭代對(duì)象、迭代器、生成器》
3.知乎:《如何更好地理解Python迭代器和生成器?》
4《PYTHON-進(jìn)階-ITERTOOLS模塊小結(jié)》
5《Python的range和xrange》
6《詳細(xì)記錄python的range()函數(shù)用法》
7《Python File next() 方法》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容