1、简介
功能:在不改变函数代码的基础上,添加额外的功能,比如计时
2、装饰器应用
2.1 无参数函数的装饰器
计算一个现有函数的运行时间,其中myfunc() 没有参数输入:
import time
from functools import wraps
def display_time(func):
# @wraps(func)
def wrap_func():
'this is wrap_func'
t1 = time.time()
func()
t2 = time.time()
print("Total time: {:.4} s".format(t2-t1))
return wrap_func
@display_time
def myfunc():
'this is myfunc'
print('myfunc is runing')
myfunc()
print('function name : {}'.format(myfunc.__name__))
print('function message: {}'.format(myfunc.__doc__))
运行结果:
myfunc is runing
Total time: 7.892e-05 s
function name : wrap_func
function message: this is wrap_func
注:myfunc()这个函数使用了装饰器,函数的__name__、__doc__被装饰器改变,函数的实际内存地址指向了wrap_func(),所以打印出来的myfunc.name、myfunc.__doc__为wrap_func()的函数名、注释。
解决方案就是引入内置的装饰器:funtools.wraps,代码如下:
import time
from functools import wraps
def display_time(func):
@wraps(func)
def wrap_func():
'this is wrap_func'
t1 = time.time()
func()
t2 = time.time()
print("Total time: {:.4} s".format(t2-t1))
return wrap_func
@display_time
def myfunc():
'this is myfunc'
print('myfunc is runing')
myfunc()
print('function name : {}'.format(myfunc.__name__))
print('function message: {}'.format(myfunc.__doc__))
运行结果
myfunc is runing
Total time: 7.057e-05 s
function name : myfunc
function message: this is myfunc
2.2 带参数函数的装饰器
知识点:
- *args 用来将参数打包成tuple给函数体调用
- **kwargs 打包关键字参数成dict给函数体调用
实现如下:
import time
from functools import wraps
def display_time(func):
@wraps(func)
def wrap_func(*args, **kwargs):
'this is wrap_func'
t1 = time.time()
res = func(*args, **kwargs)
t2 = time.time()
print("Total time: {:.4} s".format(t2-t1))
return res
return wrap_func
@display_time
def myfunc(anum, *args, **kwargs): #def myfunc(anum, atuple, adict):
'this is myfunc'
print('myfunc is runing')
print('num: {}'.format(anum))
print('tuple: {}'.format(args))
print('adict: {}'.format(kwargs))
return args
t = myfunc(3, 4, 5, 6, a=1, b=2, c=3) #,, a=1 b=2, c=3
print(t)
运行结果:
myfunc is runing
num: 3
tuple: (4, 5, 6)
adict: {‘a’: 1, ‘b’: 2, ‘c’: 3}
Total time: 0.0002067 s
(4, 5, 6)
2.3 带参数的装饰器
一个日志装饰器
from functools import wraps
def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# 打开logfile,并写入内容
with open(logfile, 'a') as opened_file:
# 现在将日志打到指定的logfile
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator
@logit()
def myfunc1():
pass
myfunc1()
# Output: myfunc1 was called
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc2()
# Output: myfunc2 was called
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串
装饰器类
待理解,具体可见 参考文献5