装饰器:
把一个函数当作参数,返回一个替代版的函数
本质上就是返回函数的函数
即:再不改变原函数的基础上,给函数增加功能
1.如何实现,在不改变函数功能的基础上,在fun函数输出之前输出‘~~~~~’
# 这是给定的函数
def fun():
print('hello python')
# 定义装饰器函数,增加功能
def outer(a):
def inner():
print('~~~~~~~~~~~~~~~')
a() # a()代表要添加功能的函数,此处代表fun()函数
return inner
fun = outer(fun) # 重新原函数,此时fun函数已经不是最先定义的函数,而是添加了功能的函数
fun()
2.练习:在每个函数输出之前,都显示一下时间
import time
# 定义装饰器函数(里面有显示时间的功能)
def decorator(fun1):
def wrapper(*args,**kwargs): # *args是多变量参数,**kwargs是关键字参数
print(time.time())
fun1(*args,**kwargs)
return wrapper
@decorator # 调用装饰器函数
def f1(func_name):
print('This is a function ' + func_name)
f1('test')
@decorator
def f2(func_name1,func_name):
print('This is a function ' + func_name1)
print('This is a function ' + func_name1)
f2('test1','test2')
@decorator
def f3(func_name1,func_name2,**kwargs):
print('This is a function ' + func_name1)
print('This is a function ' + func_name1)
print(kwargs)
f3('test1','test2',a=1,b=2,c=3)
3.定义一个计时器装饰器
import time
import random
import string
import functools
# 被装饰的函数有返回值
li = [random.choice(string.ascii_letters) for i in range(100)]
def timeit(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
@timeit
def con_add():
"""这是for循环"""
s=''
for i in li:
s+=(i+',')
print(s)
con_add()
print(con_add.__doc__) # 输出con_add函数的文档
@timeitdef
join_add():
"""这是join方法"""
print(','.join(li))
join_add()
print(join_add.__doc__) # 输出join_add函数的文档
4.比较list与map的速度
import time
import random
import string
import functools
def timeit(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
@timeit
def fun_map(n):
"""这是fun_map函数"""
return list(map(lambda x:x*2,range(n)))
print(fun_map(1000))
@timeit
def fun_list(n):
"""这是fun_list函数"""
return [i*2 for i in range(n)]
print(fun_list(1000))
5.创建装饰器,要求如下:
(1)创建add_log装饰器,被装饰的函数打印日志信息
(2)日志格式为:[字符串时间] 函数名:xxx, 运行时间:xxx 运行返回结果:xxx
import time
import functools
def add_log(add):
@functools.wraps(add) # 保留被装饰函数的函数名和帮助
def wrapper(*args,**kwargs):
start_time = time.time()
res = add(*args,**kwargs)
end_time = time.time()
print('[%s] 函数名:%s,运行时间为:%.6f,运行返回值结果:%d' %(time.ctime(),add.__name__,end_time - start_time,res))
return res
return wrapper
@add_log
def add(x,y):
time.sleep(1)
return x+y
print(add(1,10))
6.输入用户,判断用户是否为root用户,如果是,则可以添加学生信息,如果不是,就报错
# 这是第一种方法(只能接收一串字符)
def judge(add_student):
def wrapper(args):
a=input('请输入用户:')
if a=='root':
res = add_student(args)
return res
else:
print('error,你没有这个权限')
return wrapper
@judge
def add_student(name):
print('添加学生信息...')
add_student('root')
def del_studenf():
print('删除学生信息...')
# 这是第二种方法(以字典的形式接收用户输入)
import functools
import inspect
def judge(fun):
@functools.wraps(fun)
def wrapper(*args,**kwargs): # inspect.getcallargs返回值是字典,key值为:形参,value值为:形参对应实参
inspect_res = inspect.getcallargs(fun,*args,**kwargs)
print('inspect_res的返回值为:%s' %inspect_res)
if inspect_res.get('name') == 'root':
res=fun(*args,**kwargs)
return res
else:
print('not root user')
return wrapper
@judge
def add_student(name):
print('添加学生信息...')
add_student('root')
7.写装饰器resquired_int
条件如下:
(1)确保函数接收到的每个参数都是整数 (如何判断变量的类型)
(2)如果不是整数,抛出异常raise TypeError(‘参数必须为整型’)
import functools
def resquired_int(fun):
@functools.wraps(fun)
def wrapper(*args,**kwargs):
for i in args + tuple(kwargs.values()):
if not isinstance(i,int):
raise TypeError('参数必须为整数')
else:
return fun(*args,**kwargs)
return wrapper
@resquired_int
def add(*args,**kwargs):
return sum(args + tuple(kwargs.values()))
print(add(1,2,2,3,5,a=1,e=3))