一些基本概念
1 容器
可以詢問某個元素是否包含其中类垦,如list磨澡,set,tuples,dict等都是容器
2 迭代器(iterator)
1)迭代器是一個帶狀態(tài)的對象指巡,任何實現(xiàn)了iter和next__方法的對象都是迭代器(python2:任何實現(xiàn)next()方法的對象都是迭代器)。
2)其中iter返回迭代器本身隶垮,next返回容器中的下一個值藻雪。如果容器中沒有更多元素了,則拋出Stopiteration異常狸吞。
因此勉耀,可以把迭代器理解成一個帶有流水線的工程,我們每次詢問他時蹋偏,他就給我們返回下一個值便斥。迭代器會把所有的值都存儲在內(nèi)存中。
2.1 next()
next()函數(shù) 用來返回文件的下一行/下一個值威始,直到促發(fā)STopIteration枢纠。
《Python File next() 方法》
2.2 iter()
用處:把可迭代對象變?yōu)榈鳌?/p>
3 可迭代對象(iterable)
凡是可以返回一個迭代器的對象都可以稱之為可迭代對象(除了上面提到的list,tuples,dict等容器外,還有很多其他對象也是可迭代對象黎棠。比如晋渺,打開狀態(tài)的files.
我的理解是所有可以使用 for .. in .. 語法的對象都可以叫做一個迭代對象。
但是迭代器把所有的值都存儲到了內(nèi)存中脓斩,如果有大量數(shù)據(jù)的話木西,這個方式就會占用大量內(nèi)存。
注:很多容器都是可迭代對象随静,但并不是所有容器都是可迭代對象.
下面的例子可以幫助更好的理解可迭代對象八千。
>>> 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就是一個可迭代對象燎猛×道Γ可迭代對象和容器一樣是一種通俗的叫法,并不是指某種具體的數(shù)據(jù)類型扛门,列表是可迭代對象鸠信,字典是可迭代對象,集合也是可迭代對象论寨。
我們用 liter() 函數(shù)可以把可迭代對象變?yōu)榈鲗ο蟆?/p>
上面代碼中星立,y和z是兩個獨立的迭代器爽茴。迭代器內(nèi)部持有一個狀態(tài),該狀態(tài)用于記錄當前迭代所在的位置绰垂,以方便下次迭代的時候獲取正確的元素室奏。迭代器有一種具體的迭代器類型,比如list_iterator劲装,set_iterator胧沫。可迭代對象實現(xiàn)了iter方法占业,該方法返回一個迭代器對象绒怨。
當運行以下代碼時:
x = [1, 2, 3]
for elemments in x:
...
實際執(zhí)行情況是:
4 生成器(generator)
生成器其實是一種特殊的迭代器。它和一般迭代器不同的地方在于谦疾,我們 只可以讀取它一次南蹂,因為它并不把所有的值放在內(nèi)存中,它是實時地生成數(shù)據(jù):
>>> mygenerator = (x*x for x in range(3)) #range后面會介紹
>>> for i in mygenerator :
... print(i)
結(jié)果:
0
1
4
生成器只能讀取一次是什么意思念恍?舉個例子:
# -*- coding: UTF-8 -*-
def mygenerator(n): #建一個生成器
for x in range(n):
yield int(x)
y = mygenerator(5)
z = sum(y) # 使用一次生成器六剥。遍歷mygenerator中所有數(shù),并相加
for i in y: #第二次使用生成器
print(i) #print不會有任何結(jié)果峰伙,因為已經(jīng)使用過一次生成器疗疟。
本節(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ù).
更具體一點的說明:
《詳細記錄python的range()函數(shù)用法》
和range()函數(shù)相似的策彤,還有個xrange()函數(shù),具體見下面說明:
xrange()
參數(shù)與range()函數(shù)一樣顿膨,不一樣的地方在于锅锨,xrange()生成的不是一個數(shù)組,而是一個生成器恋沃。
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的列表,預先占用內(nèi)存户辞;但是xrange只會生成xrange生成器泌类,需要用到具體函數(shù)時,再占用相應的內(nèi)存底燎。所以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 關(guān)鍵詞
yield
是一個類似 return
的關(guān)鍵字,只是這個函數(shù)返回的是個生成器苞轿。
>>> 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)調(diào)用createGenerator()這個函數(shù)的時候茅诱,函數(shù)內(nèi)部的代碼并不立馬執(zhí)行 ,這個函數(shù)只是返回一個生成器對象搬卒。
只有當我們使用for進行迭代的時候瑟俭,函數(shù)內(nèi)代碼才會執(zhí)行。
第一次迭代時,函數(shù)從開始一直執(zhí)行到 yield這個 關(guān)鍵字秀睛,然后返回 yield 后的值(即ii)作為第一次迭代的返回值(即將0作為返回值).每次執(zhí)行這個函數(shù)尔当,都會繼續(xù)執(zhí)行你在函數(shù)內(nèi)部定義的那個循環(huán)的下一次,再返回那個值蹂安。例如,第二次執(zhí)行锐帜,迭代返回值為11=1田盈。當我們不斷調(diào)用,這個過程會一直持續(xù)缴阎,直到?jīng)]有可以返回的值為止允瞧。
生成器下一次迭代是從上一次結(jié)束的地方開始,而不會從頭開始蛮拔。比如第一次迭代后述暂。第二次迭代是從i=1開始,而不是從i=0開始建炫。
如果生成器內(nèi)部沒有定義 yield 關(guān)鍵字畦韭,那么這個生成器被認為成空的。這種情況可能因為是循環(huán)進行沒了肛跌,或者是沒有滿足 if/else 條件艺配。
迭代器有關(guān)工具:itertools
itertools 是一個模塊,集合了眾多的迭代函數(shù)衍慎,功能非常強大转唉,具體可以見以下內(nèi)容
《PYTHON-進階-ITERTOOLS模塊小結(jié)》
參考資料
1《(譯)Python關(guān)鍵字yield的解釋》
2.《完全理解 Python 迭代對象、迭代器稳捆、生成器》
3.知乎:《如何更好地理解Python迭代器和生成器赠法?》
4《PYTHON-進階-ITERTOOLS模塊小結(jié)》
5《Python的range和xrange》
6《詳細記錄python的range()函數(shù)用法》
7《Python File next() 方法》