Python--裝飾器
阿新 • • 發佈:2017-10-27
sign 註意 time 裝飾 app ron light wrap 操作
這樣還不能滿足我們的需求,我們想給foo函數傳參數的話,如何處理?
func函數通過*args,**kwargs接收實參即可完美實現!
裝飾器的應用場景,較為經典的有插入日誌、性能測試、事務處理等。 上代碼:
def foo(): print(‘foo‘)
此段代碼,如果我們想在不改變原有功能的基礎上添加新功能,可以這樣做:
def foo(): print(‘foo‘) def wrapper(func): def inner(): print(‘before‘) func() print(‘after‘) return inner foo=wrapper(foo) foo()
打印結果:
before
foo
after
Python提供了一個語法糖來降低字符輸入量。
def wrapper(func): def inner(): print(‘before‘) func() print(‘after‘) return inner @wrapper #wrapper=wrapper(foo) def foo(): print(‘foo‘) foo()
打印結果:
before
foo
after
讓我們來關註一下@wrapper的寫法,在foo函數定義上加上這一行與另外寫foo = wrapper(foo)完全等價,@並沒有另外的魔力。
除了字符輸入少了一些,還有一個額外的好處:這樣看上去更有裝飾器的感覺。
上代碼:
def wrapper(func): def inner(sth): print(‘before‘) func(sth) print(‘after‘) return inner @wrapper #wrapper=wrapper(foo) def foo(sth): print(sth) foo(‘apple‘)
打印結果:
before
apple
after
這個是傳一個參數的情況,如果我們想傳的參數很多,除了多個位置參數之外,還想要傳關鍵字參數,這個時候怎麽辦呢?
def wrapper(func): def inner(*args,**kwargs): print(‘before‘) func(*args,**kwargs) print(‘after‘) return inner @wrapper #wrapper=wrapper(foo) def foo(sth1,sth2,sth3,sth4): print(sth1,sth2,sth3,sth4) foo(‘apple‘,‘orange‘,‘banana‘,‘lemon‘)
打印結果:
before
apple orange banana lemon
after
進一步,我們的foo函數有時候需要使用到返回值,然後如何處理呢?
import time def wrapper(func): def inner(*args,**kwargs): print(‘before‘) ret = func(*args,**kwargs) print(‘after‘) print(ret) return ret return inner @wrapper #foo=wrapper(foo) def foo(arg): print(arg) return 111 res=foo(‘apple‘) time.sleep(1) print(res) 打印結果: before apple after 111 111(1秒後打印)
此外,functools模塊提供有裝飾器:wraps(wrapped,assigned,updated)。
函數是有幾個特殊屬性比如函數名,在被裝飾後,上例中的函數名foo會變成包裝函數的名字inner,我們可以看下例:
def wrapper(func): def inner(*args, **kwargs): print("before...") ret = func(*args, **kwargs) print("after/...") return ret return inner @wrapper # foo = wrapper(foo) -->inner def foo(sth): print(sth) return "aaa" print(foo.__name__) 打印結果: inner
這時候wraps就體現了它的作用:它能將裝飾過的函數的特殊屬性保留。
import functools def wrapper(func): @functools.wraps(func) def inner(*args, **kwargs): print("before...") ret = func(*args, **kwargs) print("after/...") return ret return inner @wrapper # foo = wrapper(foo) -->inner def foo(sth): print(sth) return "aaa" print(foo.__name__) 打印結果: foo
關於裝飾器,一些有意思的小練習可以拿來做。
一:編寫函數,(函數執行的時間是隨機的) 二:編寫裝飾器,為函數加上統計時間的功能 三:編寫裝飾器,為函數加上認證的功能 四:編寫裝飾器,為多個函數加上認證的功能(用戶的賬號密碼來源於文件),要求登錄成功一次,後續的函數都無需再輸入用戶名和密碼 註意:從文件中讀出字符串形式的字典,可以用eval(‘{"name":"egon","password":"123"}‘)轉成字典格式 五:編寫下載網頁內容的函數,要求功能是:用戶傳入一個url,函數返回下載頁面的結果 六:為題目五編寫裝飾器,實現緩存網頁內容的功能: 具體:實現下載的頁面存放於文件中,如果文件內有值(文件大小不為0),就優先從文件中讀取網頁內容,否則,就去下載,然後存到文件中 七:還記得我們用函數對象的概念,制作一個函數字典的操作嗎,來來來,我們有更高大上的做法,在文件開頭聲明一個空字典,然後在每個函數前加上裝飾器,完成自動添加到字典的操作
Python--裝飾器