Python初探第二篇-裝飾器和叠代器,生成器
一,裝飾器
1,概念
裝飾器就是給已有的模塊添加新的功能,如登錄驗證功能,運行時間功能等。本身可以是任意可調用對象,被裝飾者也可以是任意可調用對象。
強調裝飾器的原則:1 不修改被裝飾對象的源代碼 2 不修改被裝飾對象的調用方式
裝飾器的目標:在遵循1和2的前提下,為被裝飾對象添加上新功能
2,理論基礎
要想實現裝飾器的功能,我們需要三個理論基礎:函數閉包+函數嵌套+高階函數。我們通過為如下模塊加入統計運行時間的裝飾器來講解如何使用
import time def test_func(): for i in range(5): time.sleep(0.5)
3,推導
首先我們知道要知道函數的運行時間,只需要在函數前後加上當前時間,通過差值就能計算出來。因此我們可以定義一個模塊,並傳入所求的函數的函數地址,即高階函數。
模塊中包含此函數的調用和統計時間的功能
import time def test_func(): for i in range(5): time.sleep(0.5) def decorate(func): start_time = time.time() func() end_time = time.time() print(end_time-start_time) decorate(test_func)#2.5s
這樣就實現了統計時間的功能,但是卻修改了函數的調用邏輯,因此進一步思考,我們可以在裝飾器函數內定義函數,並在此函數內調用被統計函數,即函數嵌套,並返回
代碼 如下:
import time def test_func(): for i in range(5): time.sleep(0.5) def decorate(func): def count_time(): start_time = time.time() func() end_time = time.time()print(end_time-start_time) return count_time test_func = decorate(test_func) test_func()
而python給我們提供了裝飾器語法:
import time def decorate(func): def count_time(): start_time = time.time() func() end_time=time.time() print(end_time-start_time) return count_time @decorate def test_func(): for i in range(5): time.sleep(0.5) test_func()
上面就實現了一個簡單的裝飾器,可根據需求來增加它的功能,如傳入參數,返回值等。
二,叠代器
1,概念
叠代器(iteretor)是一種遍歷容器所有或者部分元素的方法,相當於一個復雜的指針,能夠遍歷復雜的數據結構,一個容器也應該提供它自己的叠代器。
2,叠代器對象與可叠代對象
叠代器對象:即對象能夠提供遍歷它的方法,像是叠代器的一種具體表現,在Python中叠代器對象能夠提供__iter__和__next__方法來得到容器中下一個元素的值。
可叠代對象:即對象提供__iter__方法,使用該方法後得到叠代器對象,如字符串,列表元組
li=[1,2,3,4,5] li=li.__iter__() # 可叠代對象轉化成叠代器對象 print(li.__next__()) # 1
3,使用方法
dic = {"a": 1, "e": 4, "b": 2, "c": 3, "d": 4} iter_dic = dic.__iter__() # while True: try: print(next(iter_dic)) #"a" "e" "b"..... except StopIteration: #需要手動捕捉異常 break
而我們可以借助Python中強大的for循環機制來循環遍歷容器
4,for循環
#基於for循環,我們可以完全不再依賴索引去取值了 dic = {‘a‘:1,‘b‘:2,‘c‘:3} for k in dic: print(dic[k]) #for循環的工作原理 #1:執行in後對象的dic.__iter__()方法,叠代器對象.__iter,返回對象本身。得到一個叠代器對象iter_dic #2: 執行next(iter_dic),將得到的值賦值給k,然後執行循環體代碼 #3: 重復過程2,直到捕捉到異常StopIteration,結束循環
三,生成器
Python使用生成器能夠實現延時操作,何謂延時操作,即需要結果時就產生結果,不需要時就不產生。提供生成器對象有兩種方式:
1,生成器函數:和常規的函數定義一樣只不過不用return,而是使用yield來返回結果。一次只返回一個結果,在每個結果中間,掛起函數狀態,以便下次繼續返回。
2,生成器表達式:生成一個生成器對象,按需產生結果,就是叠代的時候產生具體的值。
1,生成器函數
def gensquares(n): for i in range(n): yield i ** 2 obj = gensquares(5) print(obj) # <generator object gensquares at 0x00000000021E55C8> print(next(obj)) # 0 print(next(obj)) # 1 print(next(obj)) # 4
2,生成器表達式
li = [] for i in range(5): name = "name%d" % i li.append(name) print(li) # [‘name0‘, ‘name1‘, ‘name2‘, ‘name3‘, ‘name4‘] # 列表推導 li = ["name%d" % i for i in range(5)] print(li) # [‘name0‘, ‘name1‘, ‘name2‘, ‘name3‘, ‘name4‘] # 簡潔了許多 # 生成器表達式 gens = ("name%d" % i for i in range(5)) print(gens) # <generator object <genexpr> at 0x00000000028655C8> print(next(gens)) # name0 print(next(gens)) # name1 print(next(gens)) # name2
#生成器對象就是叠代器對象
使用生成器的好處數據不會直接加載到內存,在數據量很大的情況下作用很大。比如使用內置函數如下
#print(sum([i for i in range(100000000)])) #提示計算機內存不足,程序崩潰 print(sum((i for i in range(1000000000)))) #程正常運行
註意事項:生成器對象是一種叠代器對象,它們都只能遍歷一次,而可叠代對象可以多次遍歷。
Python初探第二篇-裝飾器和叠代器,生成器