要理解python裝飾器,首先要明白在python中,函式也是一種物件,因此可以把定義函式時的函式名看作是函式物件的乙個引用。既然是引用,因此可以將函式賦值給乙個變數,也可以把函式作為乙個引數傳遞或返回。同時,函式體中也可以再定義函式。
可以通過編寫乙個純函式的例子來還原裝飾器所要做的事。
def
decorator
(func):
defwrap
(): print("doing someting before executing func()")
func()
print("doing someting after executing func()")
return wrap
deffun_test
(): print("func")
fun_test = decorator(fun_test)
fun_test()
# output:
# doing someting before executing func()
# func
# doing someting after executing func()
fun_test
所指向的函式的引用傳遞給decorator()
函式
decorator()
函式中定義了wrap()
子函式,這個子函式會呼叫通過func
引用傳遞進來的fun_test()
函式,並在呼叫函式的前後做了一些其他的事情
decorator()
函式返回內部定義的wrap()
函式引用
fun_test
接收decorator()
返回的函式引用,從而指向了乙個新的函式物件
通過fun_test()
呼叫新的函式執行wrap()
函式的功能,從而完成了對fun_test()
函式的前後裝飾
在python中可以通過@
符號來方便的使用裝飾器功能。
def
decorator
(func):
defwrap
(): print("doing someting before executing func()")
func()
print("doing someting after executing func()")
return wrap
@decorator
deffun_test
(): print("func")
fun_test()
# output:
# doing someting before executing func()
# func
# doing someting after executing func()
裝飾的功能已經實現了,但是此時執行:
print(fun_test.__name__)
# output:
# wrap
fun_test.__name__
已經變成了wrap
,這是應為wrap()
函式已經重寫了我們函式的名字和注釋文件。此時可以通過functools.wraps
來解決這個問題。wraps
接受乙個函式來進行裝飾,並加入了複製函式名稱、注釋文件、引數列表等等功能。這可以讓我們在裝飾器裡面訪問在裝飾之前的函式的屬性。
更規範的寫法:
from functools import wraps
defdecorator
(func):
@wraps(func)
defwrap
(): print("doing someting before executing func()")
func()
print("doing someting after executing func()")
return wrap
@decorator
deffun_test
(): print("func")
fun_test()
print(fun_test.__name__)
# output:
# doing someting before executing func()
# func
# doing someting after executing func()
# fun_test
通過返回乙個包裹函式的函式,可以模仿wraps裝飾器,構造出乙個帶引數的裝飾器。
from functools import wraps
defloginfo
(info='info1'):
defloginfo_decorator
(func):
@wraps(func)
defwrap_func
(*args, **kwargs):
print(func.__name__ + ' was called')
print('info: %s' % info)
return func(*args, **kwargs)
return wrap_func
return loginfo_decorator
@loginfo()
deffunc1
():pass
func1()
# output:
# func1 was called
# info: info1
@loginfo(info='info2')
deffunc2
():pass
func2()
# output:
# func2 was called
# info: info2
通過編寫類的方法也可以實現裝飾器,並讓裝飾器具備繼承等物件導向中更實用的特性
首先編寫乙個裝飾器基類:
from functools import wraps
class
loginfo:
def__init__
(self, info='info1'):
self.info = info
def__call__
(self, func):
@wrap
defwrap_func
(*args, **kwargs):
print(func.__name__ + ' was called')
print('info: %s' % self.info)
self.after() # 呼叫after方法,可以在子類中實現
return func(*args, **kwargs)
return wrap_func
defafter
(self):
pass
@loginfo(info='info2')
deffunc1
():pass
# output:
# func1 was called
# info: info1
再通過繼承loginfo
類,擴充套件裝飾器的功能:
class
loginfo_after
(loginfo):
def__init__
(self, info2='info2', *args, **kwargs):
self.info2 = info2
super(loginfo_after, self).__init__(*args, **kwargs)
defafter
(self):
print('after: %s' % self.info2)
@loginfo_after()
deffunc2
():pass
func2()
# output:
# func2 was called
# info: info1
# after: info2
python高階裝飾器 Python裝飾器高階
對帶引數的函式進行裝飾 對帶引數的函式進行裝飾,內嵌包裝函式的形參和返回值與原函式相同,裝飾函式返回內嵌包裝函式物件 def deco func def deco a,b print before myfunc called.ret func a,b print after myfunc calle...
Python高階特性之裝飾器
裝飾器 定義乙個裝飾函式,函式必須返回乙個閉包 閉包就是執行時所需要的外部變數 函式物件,關於閉包的具體介紹,可參考函式,並且被裝飾的函式會被python自動傳遞給裝飾函式,作為裝飾函式的乙個引數。裝飾器的具體定義 1 把要裝飾的方法作為輸入引數 2 在函式體內可以進行任意的操作 可以想象其中會有很...
python基礎高階之裝飾器
一 閉包 1 閉包概念 def fn num 閉包的基本格式 def fn in print s num return fn in ret fn 30 ret 以上,ret fn 30 做了一下幾件事情 1,讓fn in指向某個記憶體空間 函式 2,在這個空間中建立乙個num指向30 3,把fn i...