Python-迭代器相關概念

各概念關系圖

一些基本概念


1 容器

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

2 迭代器(iterator)


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

因此,可以把迭代器理解成一個帶有流水線的工程,我們每次詢問他時,他就給我們返回下一個值。迭代器會把所有的值都存儲在內存中。

2.1 next()

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

2.2 iter()

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

3 可迭代對象(iterable)


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

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

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

 >>> 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就是一個可迭代對象??傻鷮ο蠛腿萜饕粯邮且环N通俗的叫法,并不是指某種具體的數據類型,列表是可迭代對象,字典是可迭代對象,集合也是可迭代對象。

我們用 liter() 函數可以把可迭代對象變?yōu)榈鲗ο蟆?/p>

上面代碼中,y和z是兩個獨立的迭代器。迭代器內部持有一個狀態(tài),該狀態(tài)用于記錄當前迭代所在的位置,以方便下次迭代的時候獲取正確的元素。迭代器有一種具體的迭代器類型,比如list_iterator,set_iterator??傻鷮ο髮崿F了iter方法,該方法返回一個迭代器對象。
當運行以下代碼時:

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

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

迭代對象--->迭代器

4 生成器(generator)


生成器其實是一種特殊的迭代器。它和一般迭代器不同的地方在于,我們 只可以讀取它一次,因為它并不把所有的值放在內存中,它是實時地生成數據:

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

結果:
0
1
4

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

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


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

for i in y:    #第二次使用生成器
    print(i)   #print不會有任何結果,因為已經使用過一次生成器。

本節(jié)中其他相關函數的意思:

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

更具體一點的說明:
《詳細記錄python的range()函數用法》

和range()函數相似的,還有個xrange()函數,具體見下面說明:

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

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

舉例:

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

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

比如,如果是range(1000),那個range會直接生成0-1000的列表,預先占用內存;但是xrange只會生成xrange生成器,需要用到具體函數時,再占用相應的內存。所以xrange做循環(huán)的性能比range好,尤其是返回很大的時候,盡量用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)

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

5 yield 關鍵詞


yield 是一個類似 return 的關鍵字,只是這個函數返回的是個生成器。

>>> 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

當我們用print(mygenerator)調用createGenerator()這個函數的時候,函數內部的代碼并不立馬執(zhí)行 ,這個函數只是返回一個生成器對象。

只有當我們使用for進行迭代的時候,函數內代碼才會執(zhí)行。

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

如果生成器內部沒有定義 yield 關鍵字,那么這個生成器被認為成空的。這種情況可能因為是循環(huán)進行沒了,或者是沒有滿足 if/else 條件。

迭代器有關工具:itertools

itertools 是一個模塊,集合了眾多的迭代函數,功能非常強大,具體可以見以下內容

《PYTHON-進階-ITERTOOLS模塊小結》


參考資料

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

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容