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())
can_run = Flase
print(func())
注意:@wraps接受?個(gè)函數(shù)來(lái)進(jìn)?裝飾牢贸,并加?了復(fù)制函數(shù)名稱塘装、注釋?檔险毁、參數(shù)列表 等等的功能疾忍。這可以讓我們?cè)谘b飾器??訪問(wèn)在裝飾之前的函數(shù)的屬性。
使?場(chǎng)景
授權(quán)(Authorization)
裝飾器能有助于檢查某個(gè)?是否被授權(quán)去使??個(gè)web應(yīng)?的端點(diǎn)(endpoint)黑竞。它們被?量
使?于Flask和Django web框架中眨层。這?是?個(gè)例?來(lái)使?基于裝飾器的授權(quán):
from functools improt wraps
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated
?志(Logging)
?志是裝飾器運(yùn)?的另?個(gè)亮點(diǎn)。這是個(gè)例?:
from functools import wraps
def logit(func):
@wraps(func):
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logit
def addition_func(x):
"""Do some math."""
return x + x
return = addition_func(4)
在函數(shù)中嵌?裝飾器
我們回到?志的例?面哥,并創(chuàng)建?個(gè)包裹函數(shù)哎壳,能讓我們指定?個(gè)?于輸出的?志?件。
from functools import wraps
def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def wrapped_function(func):
log_string = func.__name__ + " was called"
print(log_string)
# 打開(kāi)logfile尚卫,并寫(xiě)入內(nèi)容
with open(logfile, 'a') as open_file:
# 現(xiàn)在將日志打到指定的logfile
opened_file.write(log_string + '\n')
return wrapped_function
return logging_decorator
@logit()
def myfuncl():
pass
myfunc1()
# Output: myfunc1 was called
# 現(xiàn)在?個(gè)叫做 out.log 的?件出現(xiàn)了归榕,??的內(nèi)容就是上?的字符串 @logit(logfile='func2.log')
def myfunc2():
pass
myfunc2():
pass
myfunc2()
# Output: myfunc2 was called
# 現(xiàn)在?個(gè)叫做 func2.log 的?件出現(xiàn)了,??的內(nèi)容就是上?的字符串
裝飾器類
現(xiàn)在我們有了能?于正式環(huán)境的logit
裝飾器吱涉,但當(dāng)我們的應(yīng)?的某些部分還?較脆弱
時(shí)刹泄,異常也許是需要更緊急關(guān)注的事情。??說(shuō)有時(shí)你只想打?志到?個(gè)?件怎爵。?有時(shí)你
想把引起你注意的問(wèn)題發(fā)送到?個(gè)email特石,同時(shí)也保留?志,留個(gè)記錄鳖链。這是?個(gè)使?繼承
的場(chǎng)景姆蘸,但?前為?我們只看到過(guò)?來(lái)構(gòu)建裝飾器的函數(shù)。
幸運(yùn)的是撒轮,類也可以?來(lái)構(gòu)建裝飾器乞旦。那我們現(xiàn)在以?個(gè)類?不是?個(gè)函數(shù)的?式,來(lái)重
新構(gòu)建logit
题山。
class logit(object):
def __init__(self, logfile='out.log'):
self.logfile = logfile
def __call__(self, func):
log_string = func.__name__ + " was called"
print(log_string)
# 打開(kāi)logfile并寫(xiě)?
with open(self.logfile, 'a') as opened_file:
# 現(xiàn)在將?志打到指定的?件
opened_file.write(log_string + '\n')
# 現(xiàn)在兰粉,發(fā)送?個(gè)通知
self.notify() def notify(self):
# logit只打?志,不做別的
pass
這個(gè)實(shí)現(xiàn)有?個(gè)附加優(yōu)勢(shì)顶瞳,在于?嵌套函數(shù)的?式更加整潔玖姑,?且包裹?個(gè)函數(shù)還是使?
跟以前?樣的語(yǔ)法:
@logit()
def myfunc1():
pass
現(xiàn)在愕秫,我們給logit
創(chuàng)建?類,來(lái)添加email的功能(雖然email這個(gè)話題不會(huì)在這?展開(kāi))焰络。
class email_logit(logit):
'''
?個(gè)logit的實(shí)現(xiàn)版本戴甩,可以在函數(shù)調(diào)?時(shí)發(fā)送email給管理員
'''
def __init__(self, email='admin@myproject.com', *args, **kwargs)
self.email = email
super(logit, self).__init__(*args, **kwargs)
def notify(self):
# 發(fā)送?封email到self.email Python進(jìn)階
# 這?就不做實(shí)現(xiàn)了
pass
從現(xiàn)在起,@email_logit
將會(huì)和@logit
產(chǎn)?同樣的效果闪彼,但是在打?志的基礎(chǔ)上甜孤,還
會(huì)多發(fā)送?封郵件給管理員。