在上一個例子里,其實我們已經(jīng)創(chuàng)建了一個裝飾器!現(xiàn)在我們修改下上一個裝飾器,并編寫一個稍微更有用點的程序:
def a_new_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
def a_function_requiring_decoration():
print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()
a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
你看明白了嗎?我們剛剛應(yīng)用了之前學(xué)習(xí)到的原理。這正是python中裝飾器做的事情!它們封裝一個函數(shù),并且用這樣或者那樣的方式來修改它的行為?,F(xiàn)在你也許疑惑,我們在代碼里并沒有使用@符號?那只是一個簡短的方式來生成一個被裝飾的函數(shù)。這里是我們?nèi)绾问褂聾來運行之前的代碼:
@a_new_decorator
def a_function_requiring_decoration():
"""Hey you! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
希望你現(xiàn)在對Python裝飾器的工作原理有一個基本的理解。如果我們運行如下代碼會存在一個問題:
print(a_function_requiring_decoration.__name__)
# Output: wrapTheFunction
這并不是我們想要的!Ouput輸出應(yīng)該是“a_function_requiring_decoration”。這里的函數(shù)被warpTheFunction替代了。它重寫了我們函數(shù)的名字和注釋文檔(docstring)。幸運的是Python提供給我們一個簡單的函數(shù)來解決這個問題,那就是functools.wraps。我們修改上一個例子來使用functools.wraps:
from functools import wraps
def a_new_decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
"""Hey yo! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration
現(xiàn)在好多了。我們接下來學(xué)習(xí)裝飾器的一些常用場景。
藍本規(guī)范:
from functools import wraps
def decorator_name(f):
@wraps(f)
def decorated(*args, **kwargs):
if not can_run:
return "Function will not run"
return f(*args, **kwargs)
return decorated
@decorator_name
def func():
return("Function is running")
can_run = True
print(func())
# Output: Function is running
can_run = False
print(func())
# Output: Function will not run
注意:@wraps接受一個函數(shù)來進行裝飾,并加入了復(fù)制函數(shù)名稱、注釋文檔、參數(shù)列表等等的功能。這可以讓我們在裝飾器里面訪問在裝飾之前的函數(shù)的屬性。