1、什麼叫迭代 現在,我們已經獲得了一個新線索,有一個叫做“可迭代的”概念。 首先,我們從報錯來分析,好像之所以1234不可以for迴圈,是因為它不可迭代。那麼如果“可迭代”,就應該可以被for迴圈了。 這個我們知道呀,字元串、列表、元組、字典、集合都可以被for迴圈,說明他們都是可迭代的。 我們怎 ...
1、什麼叫迭代
現在,我們已經獲得了一個新線索,有一個叫做“可迭代的”概念。
首先,我們從報錯來分析,好像之所以1234不可以for迴圈,是因為它不可迭代。那麼如果“可迭代”,就應該可以被for迴圈了。
這個我們知道呀,字元串、列表、元組、字典、集合都可以被for迴圈,說明他們都是可迭代的。
我們怎麼來證明這一點呢?
1 from collections import Iterable 2 3 l = [1,2,3,4] 4 t = (1,2,3,4) 5 d = {1:2,3:4} 6 s = {1,2,3,4} 7 8 print(isinstance(l,Iterable)) 9 print(isinstance(t,Iterable)) 10 print(isinstance(d,Iterable)) 11 print(isinstance(s,Iterable))
結合我們使用for迴圈取值的現象,再從字面上理解一下,其實迭代就是我們剛剛說的,可以將某個數據集內的數據“一個挨著一個的取出來”,就叫做迭代。
2、迭代器和協議
既什麼叫“可迭代”之後,又一個歷史新難題,什麼叫“迭代器”?
雖然我們不知道什麼叫迭代器,但是我們現在已經有一個迭代器了,這個迭代器是一個列表的迭代器。
我們來看看這個列表的迭代器比起列表來說實現了哪些新方法,這樣就能揭開迭代器的神秘面紗了吧?
1 ''' 2 dir([1,2].__iter__())是列表迭代器中實現的所有方法,dir([1,2])是列表中實現的所有方法,都是以列表的形式返回給我們的,為了看的更清楚,我們分別把他們轉換成集合, 3 然後取差集。 4 ''' 5 #print(dir([1,2].__iter__())) 6 #print(dir([1,2])) 7 print(set(dir([1,2].__iter__()))-set(dir([1,2]))) 8 9 結果: 10 {'__length_hint__', '__next__', '__setstate__'} 11 12 13 iter_l = [1,2,3,4,5,6].__iter__() 14 #獲取迭代器中元素的長度 15 print(iter_l.__length_hint__()) 16 #根據索引值指定從哪裡開始迭代 17 print('*',iter_l.__setstate__(4)) 18 #一個一個的取值 19 print('**',iter_l.__next__()) 20 print('***',iter_l.__next__())
這三個方法中,能讓我們一個一個取值的神奇方法是誰?
沒錯!就是__next__
在for迴圈中,就是在內部調用了__next__方法才能取到一個一個的值。
那接下來我們就用迭代器的next方法來寫一個不依賴for的遍歷。
1 l = [1,2,3,4] 2 l_iter = l.__iter__() 3 item = l_iter.__next__() 4 print(item) 5 item = l_iter.__next__() 6 print(item) 7 item = l_iter.__next__() 8 print(item) 9 item = l_iter.__next__() 10 print(item) 11 item = l_iter.__next__() 12 print(item)
這是一段會報錯的代碼,如果我們一直取next取到迭代器里已經沒有元素了,就會拋出一個異常StopIteration,告訴我們,列表中已經沒有有效的元素了。
這個時候,我們就要使用異常處理機制來把這個異常處理掉。
1 l = [1,2,3,4] 2 l_iter = l.__iter__() 3 while True: 4 try: 5 item = l_iter.__next__() 6 print(item) 7 except StopIteration: 8 break
3、可迭代對象
我們現在是從結果分析原因,能被for迴圈的就是“可迭代的”,但是如果正著想,for怎麼知道誰是可迭代的呢?
假如我們自己寫了一個數據類型,希望這個數據類型里的東西也可以使用for被一個一個的取出來,那我們就必須滿足for的要求。這個要求就叫做“協議”。
可以被迭代要滿足的要求就叫做可迭代協議。可迭代協議的定義非常簡單,就是內部實現了__iter__方法。
迭代器生成的對象就是可迭代對象
4、生成器
Python中提供的生成器:
1.生成器函數:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行
2.生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表
生成器Generator:
本質:迭代器(所以自帶了__iter__方法和__next__方法,不需要我們去實現)
特點:惰性運算,開發者自定義
1 import time 2 def genrator_fun1(): 3 a = 1 4 print('現在定義了a變數') 5 yield a 6 b = 2 7 print('現在又定義了b變數') 8 yield b 9 10 g1 = genrator_fun1() 11 print('g1 : ',g1) #列印g1可以發現g1就是一個生成器 12 print('-'*20) #我是華麗的分割線 13 print(next(g1)) 14 time.sleep(1) #sleep一秒看清執行過程 15 print(next(g1))
1 def generator(): 2 print(123) 3 content = yield 1 4 print('=======',content) 5 print(456) 6 yield2 7 8 g = generator() 9 ret = g.__next__() 10 print('***',ret) 11 ret = g.send('hello') #send的效果和next一樣 12 print('***',ret) 13 14 #send 獲取下一個值的效果和next基本一致 15 #只是在獲取下一個值的時候,給上一yield的位置傳遞一個數據 16 #使用send的註意事項 17 # 第一次使用生成器的時候 是用next獲取下一個值 18 # 最後一個yield不能接受外部的值
1 #yield from 2 3 def gen1(): 4 for c in 'AB': 5 yield c 6 for i in range(3): 7 yield i 8 9 print(list(gen1())) 10 11 def gen2(): 12 yield from 'AB' 13 yield from range(3) 14 15 print(list(gen2())) 16 17 yield from