在之前我們常用for迴圈來遍歷基礎資料型別,能被for迴圈遍歷的物件叫做可迭代物件,字串、列表、元組、字典、集合都可以被稱作可迭代物件。
要判斷乙個物件是否未可迭代物件有兩種方法,判斷物件內部是否含有__iter__方法,2呼叫模組直接判斷物件是否為可迭代物件
from collections importiterable
l = ['
1', 2, 3, 4]
t = (1, 2, 3, 4)
d =
s =
print('
__iter__'in
dir(l))
print('
__iter__'in
dir(t))
print('
__iter__'in
dir(d))
print('
__iter__'in
dir(s))
(isinstance(l, iterable))
(isinstance(t, iterable))
(isinstance(d, iterable))
print(isinstance(s, iterable))
物件內部含有__iter__方法且含有__next__方法的就是迭代器,前面我們知道了字串、列表、元組、字典、集合都是可迭代物件,因為他們內部都有__iter__方法,那麼他們是否是迭代器?我們判斷下他們是否有__next__方法
l = ['1', 2, 3, 4]
t = (1, 2, 3, 4)
d =
s =
print('
__next__'in
dir(l))
print('
__next__'in
dir(t))
print('
__next__'in
dir(d))
print('
__next__
'in dir(s))
大家可以執行上面的**發現返回結果都是false,說明以上基礎資料型別都不是迭代器。那麼迭代器和可迭代物件到底有什麼區別呢?
兩者最大的區別是可迭代物件是不可直接取值的,可迭代器是可以取值的。what?,字串、列表、元組、字典明明都是可以取值的啊,大家注意如果拋開for迴圈大家是不是發現就不能取值了,時間上for迴圈是做了優化,把可迭代物件轉化成了迭代器再進行取值的,那麼有什麼物件是迭代器,答案就是檔案讀取本身就是乙個迭代器
f = open('register
', '
w',encoding='
utf-8')
print('
__iter__'in
dir(f))
print('
__next__
'in dir(f))
大家可已執行發現檔案兩種方法都有,說明檔案是乙個迭代器,大家用的readline就是取值的方法
下面介紹for迴圈到底做了什麼優化:
l1 = [1,2,3,4,5,6]l2 =iter(l1)
print(l2.__next__
()) #1
print(l2.__next__
()) #2
print(l2.__next__
()) #3
print(l2.__next__
()) #4
print(l2.__next__
()) #5
print(l2.__next__()) #6
l1 = [1,2,3,4,5,6]l2 =iter(l1)
print(l2.__next__
())print(l2.__next__
())print(l2.__next__
())print(l2.__next__
())print(l2.__next__
())print(l2.__next__
())print(l2.__next__())#stopiteration
報錯為stopiteration,這是因為迭代器l2的值已經取完了,大家要知道迭代器是單向取值的,每取值乙個,前面的值就會銷毀,這也是迭代器的優點,例如即使我需要1-10000的數字我也只需乙個記憶體位址來實現迭代器取值即可。
下面在解釋下為什麼我們在使用for迴圈的時候則不會報錯,其實for迴圈只是對報錯就行了異常處理。我們用while迴圈來模擬for迴圈:
l1 = [1,2,3,4,5,6]l2 =iter(l1)
while 1:
try:
print(l2.__next__
())
except
stopiteration:
break
#執行結果:12
3456
所以for迴圈的本質是先將可迭代物件變成迭代器,然後迴圈取值並對異常報錯進行處理退出迴圈實現迴圈取值的功能。
生成器的本質其實也是迭代器,生成器是在某些特定情況下我們為了節省記憶體通過程式設計來實現迭代器的功能。如何實現生成器,下面我們介紹兩種方法:1、通過函式實現生成器。2、生成器表示式
在函式內部**塊中有yied關鍵字,那麼這個函式就是生成器函式,yield的作用是會將函式程序暫停在此並返回值給生成器物件:
def func1(x):x+=1
yield x
x+=3
yield x
x+=5
yield
g = func1(5)
print(g.__next__()) #6
print(g.__next__()) #9
print(g.__next__()) #none
從上面例子可以看出將生成器物件g每採用next方法,函式就會執行到下乙個yied位置暫停並返回yield後面的值給生成器物件。可以看出迭代器是需要可迭代物件進行轉化。可迭代物件非常佔記憶體。生成器直接建立,不需要轉化,從本質就節省記憶體。
下面舉例說明生成器的優點,有這樣乙個例項,假如要你生成10w件衣服,你有兩種方案,1.一次性生成完畢。2、先將生成的衣服規格型號定好,客戶邊需要我邊生產,這樣就出現了以下兩種**:
defcloth1(n):
for i in range(n+1):
print('
衣服%s號
' %i)
cloth1(100000)
defcloth2(n):
for i in range(1,n+1):
yield
'衣服%s號
' %i
g = cloth2(10000)
for i in range(50):
print(g.__next__
())for i in range(50):
print(g.__next__())
可以看出第一種方案採用for迴圈一次性列印出所有衣服,而第二張方案採用生產器原理,你要多少我就生成多少而且在記憶體中永遠只佔乙個記憶體位址。
上面已經介紹了函式生產器的next方法,下面介紹send方法:
1、send 與next一樣,也是對生成器取值(執行乙個yield)的方法。
2、send 可以給上乙個yield 傳值
3、第一次取值永遠都是next。
4、最後乙個yield 永遠也得不到send傳的值。
def func1():count = yield 6
print(count)
count1 = yield 7
print(count1)
yield 8
g = func1()
next(g)
g.send('alex') #將'alex'傳給count
g.send('太白') #將'太白'傳給count1
#執行結果:
alex
太白
Python迭代器和生成器
先說迭代器,對於string list dict tuple等這類容器物件,使用for迴圈遍歷是很方便的。在後台for語句對容器物件呼叫iter 函式,iter 是python的內建函式。iter 會返回乙個定義了next 方法的迭代器物件,它在容器中逐個訪問容器內元素,next 也是python的...
Python迭代器和生成器
迭代器是訪問集合元素的一種方法 是可以記住遍歷的位置的物件。迭代器物件從集合的第乙個元素開始訪問,直到所有的元素被訪問 他有兩個基本的方法,iter 和next 字串,列表或遠足物件都可以用於建立迭代器 list1 1,2,3,4 it1 iter list1 建立迭代器物件 print next ...
python 迭代器和生成器
迭代器是訪問集合元素的一種方式。迭代器物件從集合的第乙個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退,不過這也沒什麼,因為人們很少在迭代途中往後退。另外,迭代器的一大優點是不要求事先準備好整個迭代過程中所有的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可...