標籤:stop 情況下 運行時 計時 元組 import 簡潔 __iter__ 載入
一,裝飾器
1,概念
裝飾器就是給已有的模組添加新的功能,如登入驗證功能,已耗用時間功能等。本身可以是任意可調用對象,被裝飾者也可以是任意可調用對象。
強調裝飾器的原則:1 不修改被裝飾對象的原始碼 2 不修改被裝飾對象的調用方式
裝飾器的目標:在遵循1和2的前提下,為被裝飾對象添加上新功能
2,理論基礎
要想實現裝飾器的功能,我們需要三個理論基礎:函數閉包+函數嵌套+高階函數。我們通過為如下模組加入統計已耗用時間的裝飾器來講解如何使用
import timedef test_func(): for i in range(5): time.sleep(0.5)
3,推導
首先我們知道要知道函數的已耗用時間,只需要在函數前後加上目前時間,通過差值就能計算出來。因此我們可以定義一個模組,並傳入所求的函數的函數地址,即高階函數。
模組中包含此函數的調用和統計時間的功能
import timedef 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 timedef 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_timetest_func = decorate(test_func)test_func()
而python給我們提供了裝飾器文法:
import timedef 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 ** 2obj = gensquares(5)print(obj) # <generator object gensquares at 0x00000000021E55C8>print(next(obj)) # 0print(next(obj)) # 1print(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)) # name0print(next(gens)) # name1print(next(gens)) # name2
#產生器對象就是迭代器對象
使用產生器的好處資料不會直接載入到記憶體,在資料量很大的情況下作用很大。比如使用內建函數如下
#print(sum([i for i in range(100000000)])) #提示電腦記憶體不足,程式崩潰print(sum((i for i in range(1000000000)))) #程正常運行
注意事項:產生器對象是一種迭代器對象,它們都只能遍曆一次,而可迭代對象可以多次遍曆。
Python初探第二篇-裝飾器和迭代器,產生器