python學習第十三天 叠代器 生成器
1.函數復習總結
# 函數 —— 2天 # 函數的定義和調用 # def 函數名(形參): #函數體 #return 返回值 #調用 函數名(實參) # 站在形參的角度上 : 位置參數,*args,默認參數(陷阱),**kwargs # 站在實參的角度上 : 按照位置傳,按照關鍵字傳 # 返回值:沒有返回值 返回一個值 返回多個值 # 接收返回值:沒有返回值不接收,返回一個值用一個變量接收,返回多個值用一個變量或者對應數目的變量接收 # 閉包函數 —— 在內部函數引用外部函數的變量 # 裝飾器函數—— 裝飾器一定是閉包函數View Code# 裝飾器的作用 : 在不改變原來函數的調用方式的情況下 在這個函數的前後添加新的功能 # 完美的符合了一個開發原則 :開放封閉原則 # 對擴展是開發的 # 對修改是封閉的 # 基礎的裝飾器 # from functools import wraps # def wrapper(func): # @wraps(func) # def inner(*args,**kwargs): # ‘‘‘在函數被調用之前添加的代碼‘‘‘ #ret = func(*args,**kwargs) # func是被裝飾的函數 在這裏被調用 # ‘‘‘在函數被調用之後添加的代碼‘‘‘ # return ret # return inner # 使用 —— @wrapper # @wrapper # def func(): #inner # pass # # func.__name__ # 帶參數的裝飾器 #@wrapper -- > @warapper(argument) # 三層嵌套函數 # def outer(形參): # def wrapper(func): # def inner(*args,**kwargs): # ‘‘‘在函數被調用之前添加的代碼‘‘‘ # ret = func(*args,**kwargs) # func是被裝飾的函數 在這裏被調用 # ‘‘‘在函數被調用之後添加的代碼‘‘‘ # return ret # return inner # return wrapper # @outer(True) # def func(): # pass # 多個裝飾器裝飾一個函數 # 俄羅斯套娃 #def wrapper1(func): # @wraps(func) # def inner(*args,**kwargs): # print(‘before 1‘) # print(‘******‘) # ret = func(*args,**kwargs) # func是被裝飾的函數 在這裏被調用 # ‘‘‘在函數被調用之後添加的代碼‘‘‘ # return ret # def wrapper2(func): # @wraps(func) # def inner(*args,**kwargs): # print(‘before 2‘) # ret = func(*args,**kwargs) # func是被裝飾的函數 在這裏被調用 # ‘‘‘在函數被調用之後添加的代碼‘‘‘ # return ret # @wrapper1 # @wrapper2 # def func(): # print(‘111‘) # 叠代器和生成器 —— 兩天 # 內置函數 —— 兩天
2.可叠代及可叠代協議
假如我現在有一個列表l=[‘a‘,‘b‘,‘c‘,‘d‘,‘e‘],我想取列表中的內容,有幾種方式?
首先,我可以通過索引取值l[0],其次我們是不是還可以用for循環來取值呀?
你有沒有仔細思考過,用索引取值和for循環取值是有著微妙區別的。
如果用索引取值,你可以取到任意位置的值,前提是你要知道這個值在什麽位置。
如果用for循環來取值,我們把每一個值都取到,不需要關心每一個值的位置,因為只能順序的取值,並不能跳過任何一個直接去取其他位置的值。
但你有沒有想過,我們為什麽可以使用for循環來取值?
for循環內部是怎麽工作的呢?
要了解for循環是怎麽回事兒,咱們還是要從代碼的角度出發。
首先,我們對一個列表進行for循環。
for i in [1,2,3,4]: print(i)
上面這段代碼肯定是沒有問題的,但是我們換一種情況,來循環一個數字1234試試
for i in 1234 print(i) 結果: Traceback (most recent call last): File "test.py", line 4, in <module> for i in 1234: TypeError: ‘int‘ object is not iterable
看,報錯了!報了什麽錯呢?“TypeError: ‘int‘ object is not iterable”,說int類型不是一個iterable,那這個iterable是個啥?
假如你不知道什麽是iterable,我們可以翻翻詞典,首先得到一個中文的解釋,盡管翻譯過來了你可能也不知道,但是沒關系,我會帶著你一步一步來分析。
叠代和可叠代協議 什麽叫叠代 現在,我們已經獲得了一個新線索,有一個叫做“可叠代的”概念。首先,我們從報錯來分析,好像之所以1234不可以for循環,是因為它不可叠代。那麽如果“可叠代”,就應該可以被for循環了。
這個我們知道呀,字符串、列表、元組、字典、集合都可以被for循環,說明他們都是可叠代的。
我們怎麽來證明這一點呢?
from collections import Iterable l = [1,2,3,4] t = (1,2,3,4) d = {1:2,3:4} s = {1,2,3,4} print(isinstance(l,Iterable)) print(isinstance(t,Iterable)) print(isinstance(d,Iterable)) print(isinstance(s,Iterable))
結合我們使用for循環取值的現象,再從字面上理解一下,其實叠代就是我們剛剛說的,可以將某個數據集內的數據“一個挨著一個的取出來”,就叫做叠代。
可叠代協議
可以被叠代要滿足的要求就叫做可叠代協議。可叠代協議的定義非常簡單,就是內部實現了__iter__方法。
3.叠代器
叠代器的概念 # 叠代器協議 —— 內部含有__next__和__iter__方法的就是叠代器 # 叠代器協議和可叠代協議 # 可以被for循環的都是可叠代的 # 可叠代的內部都有__iter__方法 # 只要是叠代器 一定可叠代 # 可叠代的.__iter__()方法就可以得到一個叠代器 # 叠代器中的__next__()方法可以一個一個的獲取值 # for循環其實就是在使用叠代器 # iterator # 可叠代對象 # 直接給你內存地址 # print([].__iter__()) # print(range(10)) #for #只有 是可叠代對象的時候 才能用for #當我們遇到一個新的變量,不確定能不能for循環的時候,就判斷它是否可叠代 # for i in l: # pass #iterator = l.__iter__() #iterator.__next__() #叠代器的好處: # 從容器類型中一個一個的取值,會把所有的值都取到。 # 節省內存空間 #叠代器並不會在內存中再占用一大塊內存, # 而是隨著循環 每次生成一個 # 每次next每次給我一個 # range # f # l = [1,2,3,45] # iterator = l.__iter__() # while True: # print(iterator.__next__()) # print(range(100000000000000)) # print(range(3)) # print(list(range(3))) # def func(): # for i in range(2000000): # i = ‘wahaha%s‘%i # return i # 生成器 —— 叠代器 # 生成器函數 —— 本質上就是我們自己寫得函數 # 生成器表達式 l = [1,2,3,4,5] for i in l: print(i) if i == 2: break for i in l: print(i)View Code
4.生成器
我們知道的叠代器有兩種:一種是調用方法直接返回的,一種是可叠代對象通過執行iter方法得到的,叠代器有的好處是可以節省內存。
如果在某些情況下,我們也需要節省內存,就只能自己寫。我們自己寫的這個能實現叠代器功能的東西就叫生成器。
Python中提供的生成器:
1.生成器函數:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行
2.生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表
生成器Generator:
本質:叠代器(所以自帶了__iter__方法和__next__方法,不需要我們去實現)
特點:惰性運算,開發者自定義
代碼
python學習第十三天 叠代器 生成器