1.迭代器回顧html
可迭代對象:Iterable
能夠直接做用於for循環的對象統稱爲可迭代對象:Iterable。由於可迭代對象裏面存在可迭代協議,因此纔會被迭代
可迭代對象包括:
列表(list)
元組(tuple)
字典(dict)
集合(set)
字符串(str)
生成器(generator)
也能夠說除了int和bool類型的數據之外,都是可迭代對象。
爲何他們能被迭代? 由於他們還有__iter__方法
可使用isinstance()判斷一個對象是不是Iterable對象。python
迭代器:Iterator
它表示的是一個數據流,Iterator對象能夠被next()函數調用並不斷返回下一個數據,直到沒有數據時拋出StopIteration錯誤。可
以把這個數據流看作是一個有序序列,但咱們卻不能提早知道序列的長度,只能不斷經過next()函數實現按需計算下一個數據,因此Iterator的計算是惰性的,
只有在須要返回下一個數據時它纔會計算。Iterator甚至能夠表示一個無限大的數據流,例如全體天然數。而使用list是永遠不可能存儲全體天然數的。
迭代器包括:
生成器(generator)都是Iterator對象
但list、dict、str雖然是Iterable,卻不是Iterator。 程序員
如何把可迭代對象變成迭代器?
python2
把list、dict、str等Iterable變成Iterator可使用iter()函數
isinstance(iter('abc'), Iterator)
python3
把list、dict、str等Iterable變成Iterator可使用__iter__()函數
from collections import Iterable
str ="abc"
print(isinstance(str.__iter__(),Iterable))算法
2.生成器 generator閉包
裝飾器的本質是閉包
生成器的本質是迭代器
python中的generator保存的是算法,真正須要計算出值的時候纔會去往下計算出值。它是一種惰性計算(lazy evaluation)。
在python中有三種方式來獲取生成器(python中提供的生成器)
1.經過生成器函數
2.經過各類推到式來實現生成器
3.經過數據的轉換也能夠獲取生成器(目前還不會)ide
1.經過生成器函數函數
def func(): print(1) yield 5 # 個人函數走到這了 print(2) yield 9 # 個人函數走到這了 g = func() # 生成一個生成器 print(g.__next__())
1.在函數中使用yield關鍵字,函數就變成了一個generator。(看到有yiled的存在就是生成器函數)
其中的yiled能夠和普通函數中的return進行比較:
普通函數碰到return就結束函數
生成器函數碰到yield不結束就掛起,進行分段執行。在執行到yiled的時候,函數會記住本次執行到的位置,當下一次調用時,就從該位置開始。
yiled特色:
1.掛起函數
2.返回值給調用者
3.接受值,能夠接受調用者傳參
注意:調用生成器函數不會獲得返回的具體的值,而是獲得一個可迭代的對象,每一次得到可迭代文件的值,就能推進函數執行,獲取新的返回值,直到函數結束
2.若是咱們循環和傳參的話,須要使用的send()函數。
send函數的做用和__next__函數同樣,都是讓生成器執行到下一個yiled
區別:
send能夠給上一個yield的位置傳遞值,不能給最後一個yield發送值,在第一次執行生成器的時候最好不要使用send(),若是非要使用的話,須要給個傳遞個空值。send(None)
send()函數的本質是next+參數
comment = yiled 2
print(comment)
若是調用的時send(10)的話,會返回2和10,由於yiled可已接收參數,來賦值給yiled左邊的變量,可是yiled的值不改變
3.生成調用方法
1.__next__方法
2.生成器調用方法(這個地方不知道當時爲何這麼作筆記)
3.send方法(本質是next+參數)
4.生成器優勢
在瞭解迭代器的時候咱們知道,迭代器是經過python語言自己實現的迭代功能,來節省內存地址的
起始生成器也是同樣,只是爲了在某些狀況下,咱們也須要節省內存,就只能本身寫。咱們本身寫的這個能實現迭代器功能的東西就叫生成器。
5.在python3中提供一種能夠直接把可迭代對象中的每個數據做爲生成器的結果進行返回
def func():
lst = ['衛龍','老冰棍','北冰洋','牛羊配']
yield from lst 至關於for item in lst:
g = func()
for i in g:
print(i) --->
2.經過推導式(把一個列表生成式的[]
改爲()
,就建立了一個generator)lua
g = (i for i in range(10)) print(g) ---> <generator object <genexpr> at 0x0000000002143D00>
3.生成器總結spa
1.生成器的本質就是一個迭代器 2.生成器必定是一個迭代器,迭代器不必定是一個生成器 3.生成器是可讓程序員本身定義的一個迭代器 4.生成器的好處,節省內存空間 5.生成器的特性 一次性的,惰性機制,從上向下 6.send至關於 next+傳值,第一次觸生成器的時候,若是使用send(None),值必須是None,通常我建議大家使用__next__ 7.python2 iter() next() python3 iter() next() __next__() __iter__() 8.yield from 將可迭代對象元素逐個返回
9.生成器沒有索引
10.調用生成器函數不會獲得返回的具體的值,而是獲得一個可迭代的對象
3.推導式code
推導式的用法 【結果 語法】 容器 就是將【】替換成想要推導的數據類型的符號 (第一個位置是結果,剩下的都是語句) 推導式: 1.列表推導式 print([item for item in range(10)]) 2.集合推導式 print({item for item in range(10)}) 3.字典推導式 print({item:item+1 for item in range(10)}) 4.生成器推導式:(最簡單的辦法是將列表推導式的[]換成()) print(i for i in range(10))--->打印出來的是生成器的內存地址,__next__纔會調用 #根據推導式寫出小於100的奇數 print([item for item in range(100) if item %2 !=0 ])
注意:
推導式不宜寫太長,可讀性差
實現小的需求時,可使用推導式,節省代碼
4.other
1.大批量的數據的時候首先要想到生成器 2.生成器的好處,很是節省內存 3.yiled既能夠返回值給調用者,又能接受參數,還能夠將函數掛起,掛起的時候返回None 4.第一次調用生成器的時候使用send裏邊的值必須是None 5.看見yield就是生成器函數 6.幾個yiled就應該對應幾個(next+count)總數 7.yiled和return的區別是:多了一個掛起,少了一個終止函數 8.生成器函數和普通函數的區別???? 1.在打印函數名()的時候,普通函數是打印函數的返回值而生成器函數打印的時生成器的內存地址,必需要函數名().__next__()才能看到返回值
2.返回值的方式不一樣,yiled和return
[x for x in dir(list) if not x.startswith('_')] 查看某個具體方法的使用: help(類名) help(list) help(類名.方法名) help(list.pop)
使用生成器獲取100以內7的倍數
def test(): for item in range(0,100): yield item ret = test() for item in range(0,100): ss =ret.__next__() if ss %7 == 0: print(ss)
生成器讀取文件
def func(): with open('t','r',encoding='utf-8')as f: for i in f: i = i.strip('\r\n') yield i g = func() for i in g: try: print(i) except StopIteration: # pass print(1)