装饰器
1. 什么是装饰器
装饰器(Decorators)是修改其它函数功能的函数。
2. 理解装饰器的基础知识
(1)函数中可以定义函数
def fun():
def inner():
print("This is a inner function!")
inner()
(2)函数可以返回一个函数对象
def fun():
def inner():
print("This is a inner function!")
return inner
(3)函数可以作为参数传递给函数
def fun(func_para):
print(func_para())
3. 装饰器例子
(1)首先定义一个装饰器decorator()
,它是个函数,主要功能是函数参数接收一个函数对象a_func
,然后定义内部函数wrapTheFunction()
对函数对象a_func
修饰(增加功能),然后将内部函数返回。
def decorator(a_func):
def wrapTheFunction:
print("您好!")
a_func()
print("谢谢!")
return wrapTheFunction
(2)定义一个待修饰的函数
def func():
print("我是函数func()")
(3)使用装饰器decorator()
修饰func()
>>>func()
我是函数func()
>>>decor_func=decorator(func)
>>>decor_func()
您好!
我是函数func()
谢谢!
可以看到,我们对函数func()
使用装饰器后,在函数本身没有改动的情况下,增加了输出“您好!”
和“谢谢!”
的功能,这就是装饰器dcorator()
的作用。
4. @
符号的用法
为了避免像上面代码那样使用装饰器时生成额外的函数变量decor_func
,使用装饰器的方法是使用@
符号声明在被修饰函数的定义之前。
@decorator
def func():
print("我是函数func()")
之后调用的func()
都是装饰器decorator()
修饰过的。
>>>func()
您好!
我是函数func()
谢谢!
5. 完整的装饰器写法
上述代码虽然实现了对函数func()
的修饰,但是上述写法会改变func()
的函数名称和注释文档。
>>>func.__name__
>>>wrapTheFunction
这显然不是我们想要的,因此完整的装饰器写法如下:
from functools import wraps
# 定义装饰器
def decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("您好!")
a_func()
print("谢谢!")
return wrapTheFunction
# 使用装饰器
@decorator
def func():
print("我是函数func()")
调用后的输出为
>>>func()
您好!
我是函数func()
谢谢!
>>>func.__name__
func
可以看到函数名称不会发生改变!
6. 装饰器模板
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
7. 装饰器应用——日志
创建日志装饰器,在函数调用时,会将函数名称写入到日志文件中。
from functools import wraps
def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def wrap_function(*args,*kwargs):
log_string=func.__name__+" was called"
print(log_string)
with open(logfile,'a') as log_f:
log_f.write(log_string+'\n')
return func(*args,**kwargs)
return wrap_function
return logging_decorator
可以看到,在logging_decorator()
的外部又增加了一层函数logit()
,这是为了传入日志文件名称logfile
这个参数,这样的结果是装饰器可以携带参数。
@logit('my_log.log')
def myfunc():
pass
8. 装饰器类——以日志为例
定义一个装饰器类,实现函数调用时将函数名称写入日志文件,发送邮件等复杂功能。
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(logfile,'a') as log_f:
log_f.write(log_string+'\n')
# 发送邮件
self.notify()
return func(*args,**kwargs)
return wrapped_function
def notify(self):
# 发送邮件
pass
使用装饰器:
@logit('my_log.log')
def myfunc():
pass