
一些基本概念
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 是一個模塊,集合了眾多的迭代函數,功能非常強大,具體可以見以下內容
參考資料
1《(譯)Python關鍵字yield的解釋》
2.《完全理解 Python 迭代對象、迭代器、生成器》
3.知乎:《如何更好地理解Python迭代器和生成器?》
4《PYTHON-進階-ITERTOOLS模塊小結》
5《Python的range和xrange》
6《詳細記錄python的range()函數用法》
7《Python File next() 方法》