装饰器:
把一个函数当作参数,返回一个替代版的函数
本质上就是返回函数的函数
即:再不改变原函数的基础上,给函数增加功能
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(10000)]
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函数的文档
@timeit
def 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(10000))
@timeit
def fun_list(n):
"""这是fun_list函数"""
return [i * 2 for i in range(n)]
print(fun_list(10000))
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
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('删除学生信息...')
#add_student('root')
# 这是第二种方法(以字典的形式接收用户输入)
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 required_ints(func):
@functools.wraps(func)
def wrapper(*args,**kwargs): # (1,2,....)
for i in args:
# if isinstance(i,int):
# pass
# else:
# print('函数所有的参数并非全是int型')
if not isinstance(i,int):
print('函数所有的参数并非都是int型')
break
else:
res = func(*args,**kwargs)
return res
return wrapper
@required_ints
def add(a,b):
return a+b
@required_ints
def mymax(a,b,c,d):
return max(a,b,c,d)
print(add(1,2.0))
8. 多个装饰器的执行顺序
def decorator_a(func):
print('Get in decorator_a')
def inner_a(*args,**kwargs):
print('Get in inner_b')
res = func(*args,**kwargs) #返回值在两个定义的函数中都要定义
return res
return inner_a
def decorator_b(func):
print('Get in decorator_b')
def inner_b(*args,**kwargs):
print('Get in inner_b')
res = func(*args,**kwargs) #返回值在两个定义的函数中都要定义,且这个返回值的结果在最后执行
return res
return inner_b
@decorator_b
@decorator_a
def f(x):
print('Get in f')
return x * 2
print(f(1))
例题:
定义装饰器log,用户判断用户是否登陆成功
定义装饰器isroot,用于判断用户是不是为root
编写这2个装饰器:先判断是否登陆成功,再判断是不是root用户
import functools
import inspect
def is_root(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':
print('is root')
res = fun(*args,**kwargs)
return res
else:
print('not root user')
return wrapper
li = ['root','westos','redhat']
def log(fun):
@functools.wraps(fun)
def inlog(name):
if name in li:
print('登陆成功')
res = fun(name)
return res
else:
print('登陆失败')
return inlog
@log
@is_root
def add_student(name): ##此处的name为inspect.getcallargs返回字典中的key值
print('添加学生信息...')
add_student('root')
9. 带参数的装饰器
import time
import functools
def log(kind):
def add_log(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
start_time = time.time()
res = func(*args,**kwargs)
end_time = time.time()
print('<%s> [%s] 函数名:%s,运行时间:%.6f,运行返回值的结果'
':%d' %(kind,time.ctime(),func.__name__,
end_time-start_time,res))
return res
return wrapper
return add_log
@log('debug')
def add(x,y):
time.sleep(1)
return x+y
add(1,10)
10. 多个装饰器的练习
编写装饰器required_types, 条件如下:
1). 当装饰器为@required_types(int,float)确保函数接收到的每一个参数都是
int或者float类型;
2). 当装饰器为@required_types(list)确保函数接收到的每一个参数都是list类型;
3). 当装饰器为@required_types(str,int)确保函数接收到的每一个参数都是str或者int类型;
4). 如果参数不满足条件, 打印 TypeError:参数必须为xxxx类型
import functools
def required_type(*kind):
def require(fun):
@functools.wraps(fun)
def wrapper(*args,**kwargs):
for i in args:
if not isinstance(i,kind):
print('函数所有的参数并非',kind)
break
else:
res = fun(*args,**kwargs)
return res
return wrapper
return require
# a = 1.0
# print(isinstance(a,(int,float)))
@required_type(int,float)
def add(a,b):
return a+b
print(add(1025,'1'))