装饰器
装饰器:
把一个函数当作参数,返回一个替代版的函数
本质就是一个返回函数的函数
装饰器的模板
#这是一个装饰器,接收一个函数func作为参数
def decorator(func):
#接下来,要建一个对函数func进行处理的函数wrapper(这是装饰器的意义所在嘛)
#这个函数是有要求的:1.接收所要处理函数func的参数(以wrapper参数接收)。2.函数func的返
#回值,需要通过wrapper的返回值传回
def wrapper(*args, **kw):
{一系列函数调用前的操作}
r = func(*args, **kw) #r保存了返回值
{一系列函数调用后的操作}
return r
return wrapper
装饰器的好处
使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。
在python里,“对修改是封闭的,对扩展是开放的”
首先我们看一个没有装饰器的例子:
运行结果:
没有实现func1()函数的调用
这个虽然实现了fun1()函数的调用,但修改了原来的代码,我们如何不修改原来的代码,实现函数功能的补充呢?
这就需要装饰器了
有了装饰器的效果:
@....调用装饰器的方法
装饰器还可以调用参数
调用可变形参
运行结果:
调用关键字参数
运行结果:
调用*args返回的是元组,调用**kwargs返回的是字典。
装饰器练习
练习一:装饰器实现一个函数计时器
比较两种连接列表元素方法用时的快慢
import random
import string
import time
import functools
li = [random.choice(string.ascii_letters) for i in range(100)]
print(li)
def timec(fun):
@functools.wraps(fun)
def wrapper(*args,**kwargs):
start_time = time.time()
res = fun(*args,**kwargs)
end_time = time.time()
print('运行时间为: %.6f' %(end_time - start_time))
return res
return wrapper
@timec
def con_add():
s = ''
for i in li:
s += (i + ',')
print(s)
@timec
def join_add():
print(','.join(li))
con_add()
join_add()
print(con_add.__doc__)
print(con_add.__name__)
@timec
def fun_list(n):
return [2 * i for i in range(n)]
@timec
def fun_map(n):
return list(map(lambda x:x*2,range(n)))
print(fun_list(100))
print(fun_map(100))
发现第一种方法能快一点
练习二:
创建装饰器, 要求如下:
- 创建add_log装饰器, 被装饰的函数打印日志信息;
- 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回值结果:xxx
import time
import functools
def add_log(fun):
@functools.wraps(fun)
def wrapper(*args,**kwargs):
start_time = time.time()
res = fun(*args,**kwargs)
end_time = time.time()
print('[%s] 函数名: %s,运行时间: %.6f,运行返回值结果: %d' %(time.ctime(),fun.__name__,end_time-start_time,res))
return res
return wrapper
@add_log
def add(x,y):
time.sleep(1)
return x + y
add(1,3)
运行结果:
练习三:
判断是否为管理员root登陆,如果为root登陆,则显示相应的信息
inspect.getcallargs返回一个字典,key值:形参 value值:对应的实参
import functools
import inspect
def is_admin(fun):
@functools.wraps(fun)
def wrapper(*args,**kwargs):
inspect_res = inspect.getcallargs(fun,*args,**kwargs)
print('inspect的返回值: %s' %inspect_res)
if inspect_res.get('name') == 'root':
res = fun(*args,**kwargs)
return res
else:
print('Permission denied!')
return wrapper
@is_admin
def add_student(name):
print('添加学生信息')
def del_student(name):
print('删除学生信息')
add_student('root')
运行结果: