先甩上参考链接:参考教程
装饰器本身是为了避免相似处理代码的重复的简化处理。
最原始的使用:
def a_new_decorator(a_func):
@wraps(a_func) #从wraps函数可以发现 decorator函数可以传参
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_require_decorator():
print('I am the function who needs some decoration to remove mu foul smell')
a_new_decorator(a_function_require_decorator)()
print(a_function_require_decorator.__name__)
output:
I am doing some boring work before executing a_func()
I am the function who needs decorator to remove foul smell
I am doing some boring work after executing a_func()
wrapTheFunction
为了可以正确输出函数的__name__, 使用@wraps decorator函数。
因为这种写法模糊了这个函数到底要干什么的重点,所以引入语法糖@
@a_new_decorator
def a_function_require_decorator():
print('I am the function who needs decorator to remove foul smell')
a_function_require_decorator()
这种方式结构清晰明了,将装饰器的部分都藏了起来,最后运行的时候只需运行这个函数。
# 规范写法
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 = False
print(func())
使用场景
1.授权(authorization)
检查某个人是否被授权使用某个web应用的端点(endpoint),常用于Flask和Django web框架。
#用于web授权的场景
from functools import wraps
def require_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
2.日志
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
result = addition_func(4)
# Output: addition_func was called
带参数的装饰器
在函数中嵌入装饰器
@my_decorator 语法实际返回一个以某个单个函数为参数的包裹参数。我们可以通过函数嵌套,使最外层函数可以传参,并且返回包裹函数。
#带参数的装饰器
from functools import wraps
def logit(logfile='out.log'):
def logging_decorator(f):
@wraps(f)
def wrapped_function(*args, **kwargs): 这里传入的参数为f的参数
args为位置参数 kwargs为关键字参数
log_string = f.__name__ + ' was_called'
print(log_string)
with open(logfile, 'a') as opened_file:
opened_file.write(log_string)
return f(*args, **kwargs) 在这里执行f
return wrapped_function
return logging_decorator
@logit()
def my_func():
pass
my_func()
#output:my_func was_called
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc2()
# Output: myfunc2 was called
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串
装饰器类
现在我们有了能用于正式环境的logit装饰器,但当我们的应用的某些部分还比较脆弱时,异常也许是需要更紧急关注的事情。比方说有时你只想打日志到一个文件。而有时你想把引起你注意的问题发送到一个email,同时也保留日志,留个记录。这是一个使用继承的场景,但目前为止我们只看到过用来构建装饰器的函数。
幸运的是,类也可以用来构建装饰器。那我们现在以一个类而不是一个函数的方式,来重新构建logit
# 装饰器类
from functools import wraps
class logit(object):
def __init__(self, logfile='out.log'):
self.logfile = logfile
def __call__(self, func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + ' was called'
print(log_string)
with open(self.logfile, 'a') as opened_file:
opened_file.write(log_string)
self.notify()
return func(*args, **kwargs)
return wrapped_function
def notify(self):
pass
@logit()
def my_func1():
pass
my_func1()
class logit_email(logit):
def __init__(self,email = 'admin@myproject.com', *args, **kwargs):
self.email = email
super(logit_email, self).__init__(*args, **kwargs)
#注意继承类时super后面的表达 args和kwargs的使用
def notify(self):
# 发送一封email到self.email
pass
@logit_email()
def my_func2():
pass
my_func2()