装饰器定义:
把一个函数当作参数,返回一个替代版的函数
本质上就是一个返回函数的函数
装饰器作用:
“在不改变原函数的基础上,给函数增加功能”
需求:在fun函数中添加#行内容
方法一:函数可能被其它模块已经调用,所以不能直接更改原函数
def fun():
#print('Welcome to westos') ##在函数内直接添加
print('Hello python!')
print('Welcome to westos') ##在函数之外添加需求信息,不适用已被调用的函数
fun()
def fun():
print('Hello python!')
def fun1():
print('Welcome to westos')
fun()
fun1()
def decorator(fun): ##定义装饰器函数
def wrapper(*args,**kwargs):定义装饰器内部函数
print('Welcome to westos') ##打印输出
fun() ##调用函数
return wrapper
@decorator ##使用装饰器给fun函数添加需求
def fun():
print('Hello python!')
fun()
注意:
decorator是用于返回wrapper(不带()表示返回函数,带()表示返回运行结果)
需求:在函数运行前打印时间
import time
def decorator(fun):
def wrapper():
print(time.time()) ##打印linux系统时间,从1970年1月1日开始计算时间
fun()
return wrapper
def f1():
print('This is a function')
f = decorator(f1) ##调用装饰器方式一,写在函数后面
f()
import time
def decorator(fun):
def wrapper():
print(time.time())
fun()
return wrapper
@decorator ##调用装饰器方式二,写在函数前面
def f1():
print('This is a function')
f1()
装饰器可以设置可变参数
import time
def decorator(func):
def wrapper(*args,**kwargs):
print(time.time())
func(*args,**kwargs)
return wrapper
@decorator
def f1(func_name):
print('This is a function ' + func_name)
@decorator
def f2(func_name1,func_name2):
print('This is a function ' + func_name1)
print('This is a function ' + func_name2)
f1('test')
f2('test1','test2')
import time
def decorator(func):
def wrapper(*args,**kwargs):
print(time.time())
func(*args,**kwargs)
return wrapper
@decorator
def f3(func_name1,func_name2,**kwargs):
print('This is a function ' + func_name1)
print('This is a function ' + func_name2)
print(kwargs)
f3('test1','test2',a=1,b=2,c='westos')
应用一:装饰器实现一个函数计时器,计算函数运行时间
注意:
被装饰的函数有返回值时,需要在装饰器中对函数的运行结果处理(用一个变量保存函数 ,返回返回值)
用列表方式实现计算2 * n函数的时间
用高阶函数和匿名函数方式实现计算2 * n所用的时间
import time
def timetest(fun):
def wrapper(*args,**kwargs):
start_time = time.time()
res = fun(*args,**kwargs) ##在装饰器中对函数的运行结果进行处理
end_time = time.time()
print('Running time is: %.6f' %(end_time - start_time))
return res
return wrapper
@timetest ##调用装饰器
def fun_list(n): ##列表方式
"""This is the fun_list function"""
return [2 * i for i in range(n)]
@timetest
def fun_map(n): ##高阶函数方式
"""This is the fun_map function"""
return list(map(lambda x:x*2,range(n)))
print(fun_list(100))
print(fun_map(100))
可以看出列表生成式的运行时间更短
如何保留被装饰函数的函数名和帮助信息文档
import time
import functools ##导入函数工具
def timetest(fun):
"""This is a decorator fun"""
@functools.wraps(fun) ##保留被装饰的函数名和帮助信息文档,否则默认返回wrapper函数的帮助信息文档
def wrapper(*args,**kwargs):
"""This is a wrapper function"""
start_time = time.time()
res = fun(*args,**kwargs)
end_time = time.time()
print('Running time is: %.6f' %(end_time - start_time))
return res
return wrapper
@timetest
def fun_list(n):
"""This is the fun_list function"""
return [2 * i for i in range(n)]
@timetest
def fun_map(n):
"""This is the fun_map function"""
return list(map(lambda x:x*2,range(n)))
print(fun_list.__doc__) ##打印函数帮助信息
print(fun_list.__name__) ##打印函数名
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,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_types(*kind):
def required(fun):
@functools.wraps(fun)
def wrapper(*args,**kwargs):
for i in args:
if not isinstance(i,kind):
print('TypeError:参数必须为%s,%s类型' %kind)
exit()
else:
res = fun(*args,**kwargs)
return res
return wrapper
return required
@required_types(float,float)
def add(a,b):
return a+b
print(add(1.0,2)) ##对应第一张图
print(add(1.0,2.0)) ##对应第二张图
def decorator_a(fun):
def inner_a(*args,**kwargs):
print('This is inner_a')
return fun(*args,**kwargs)
return inner_a
def decorator_b(fun):
def inner_b(*args,**kwargs):
print('This is inner_b')
return fun(*args,**kwargs)
return inner_b
@decorator_b
@decorator_a
def f(x):
print('This is f')
return x*2
print(f(1))