1.装饰器定义
把一个函数当作参数,返回一个替代版的函数
本质上就是一个返回函数的函数
作用:在不改变原函数的基础上,给函数增加功能
2.装饰器的应用
2.1没有使用装饰器的情况
方法一:
def fun():
print('hello westos')
fun()
打印结果
hello westos
给上面函数内添加内容:
def fun():
print('hello world')
print('hello westos')
fun()
打印结果 成功添加了但是改变了函数的整体内容
hello world
hello westos
方法二:
def fun():
#print('hello world')
print('hello westos')
#fun()
def outher():
print('hello world')
fun()
outher()
打印结果 成功添加但是改变了调用函数名称
hello world
hello westos
方法三:
import time 导入时间
def decorator(fun): 定义装饰器函数
def wrapper(): 定义装饰器内部函数也就是要添加的函数(元素)
print(time.time()) 定义添加内容
fun() 形参:代表下方的f1()函数
return wrapper 返回warpper函数 让warpper函数运行,若不返回则下方调用无效,
def f1(): 不加括号表示返回函数本身,带括号表示返回结果,此函数没有结果
print('meng')
f = decorator(f1) 定义名称f 调用装饰器函数
f() 函数名发生改变
打印结果
1587872633.0011702
meng
2.2使用装饰器给函数增添新的功,在已经写好的函数上添加新内容
import time 导入时间函数
def desorator(fun): 定义装饰器函数
def wrapper(*args,**kwargs): 定义装饰器内部函数
print(time.time()) 打印时间从1970年开始
fun(*args,**kwargs) 调用函数
return warpper 返回函数
@desorator 使用装饰器给f函数添加打印时间功能
def f():
print('hello westos')
f()
打印结果
1587875340.6591613
hello westos
2.3装饰器传入参数
import time
def decorator(fun):
def wrapper(*args,**kwargs):
print(time.time())
fun(*args,**kwargs)
return wrapper
@decorator
def f(fun_name1,fun_name2,**kwargs):
print('hello westos' + fun_name1)
print('hello westos' + fun_name2)
print(kwargs)
f('test1','test2',a=1,b=2,c='westos')
打印结果
1587880978.5839212
hello westostest1
hello westostest2
{'a': 1, 'b': 2, 'c': 'westos'}
2.4装饰器设置可变参数
import time
def decorator(fun):
def wrapper(*args,**kwargs):
print(time.time())
fun(*args,**kwargs)
return wrapper
@decorator
def f(fun_name1,fun_name2,**kwargs):
print('hello westos' + fun_name1)
print('hello westos' + fun_name2)
f('test1','test2')
打印结果
1587881108.6572278
hello westostest1
hello westostest2
2.5装饰器可以设置关键字参数
import time
def decorator(fun):
def wrapper(*args,**kwargs):
print(time.time())
fun(*args,**kwargs)
return wrapper
@decorator
def f(fun_name1,fun_name2,**kwargs):
print('hello westos' + fun_name1)
print('hello westos' + fun_name2)
print(kwargs)
f('test1','test2',a=1,b='hello',c='python')
打印结果
1587881250.1230538
hello westostest1
hello westostest2
{'a': 1, 'b': 'hello', 'c': 'python'}
应用场景及习题
装饰器实现一个函数计时器
i
mport time 时间模块(import time)
import functools 用于高阶函数:指那些作用于函数或者返回其它函数的函数,通常只要是可以被当做函数调用的对象就是这个模块的目标
def timetest(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
@timetest
def fun_list(n):
"""这是一个fun_list函数"""
return [2 *i for i in range(n)] 列表生成式
@timetest
def fun_map(n):
"""这是一个fun_map函数"""
return list(map(lambda x:x*2,range(n))) 匿名函数
print(fun_list(1000))
print(fun_map(1000)
打印结果
import random
import string
import time
import functools
li = [random.choice(string.ascii_letters) for i in range(5)]
print(li)
def timetest(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
@timetest
def con_add():
"""这是一个con_add函数"""
s = ' '
for i in li:
s += (i+',')
print(s)
@timetest
def join_add():
"""这是一个jion_add函数"""
print(','.join(li))
con_add()
join_add()
print(con_add.__doc__)
print(join_add.__doc__)
打印结果
['J', 'P', 'Q', 'K', 'S']
J,P,Q,K,S,
运行时间为:0.000015
J,P,Q,K,S
运行时间为:0.000005
这是一个con_add函数
这是一个jion_add函数
创建装饰器, 要求如下:
- 创建add_log装饰器, 被装饰的函数打印日志信息;
- 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回
值结果:xxx
time.sleep()函数推迟调用线程的运行,可通过参数secs指秒数,表示进程挂起的时间语法格式:time.sleep(t)
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(2,5)
打印结果
[Sun Apr 26 15:46:02 2020] 函数名:add 运行时间:1.001615,运行返回值结果:7
之前的装饰器传入的参数都是函数,返回值也是函数
现在给装饰器传入一般参数
装饰器也是函数,现在只需要再装饰器外面再加一层装饰器就可以变为函数传入函数
编写装饰器required_types, 条件如下:
1). 当装饰器为@required_types(int,float)确保函数接收到的每一>个参数都是int或者float类型;
2). 当装饰器为@required_types(list)确保函数接收到的每一个参数
都是list类型;
3). 当装饰器为@required_types(str,int)确保函数接收到的每一个>参数都是str或者int类型;
4). 如果参数不满足条件, 打印 TypeError:参数必须为xxxx类型
sinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance()。
isinstance(object, classinfo)
>>>a = 2
>>> isinstance (a,int)
True
>>> isinstance (a,str)
False
>>> isinstance (a,(str,int,list)) 是元组中的一个返回 True
True
import functools
def required_types(*kind): 最外面定义一个装饰器*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) 调用最外层函数float浮点型,表示有小数点的数值整型
def add(x,y):
return x+y
print(add(3.3,3.3))
print(add(2,5.5))
打印结果6.6
TypeError:参数必须为<class 'float'>,<class 'float'>类型’
多个装饰器执行顺序
def decorator_a(fun): 第一个装饰器
def inner_a(*args,**kwargs):
print('get in inner_a')
return fun(*args,**kwargs)
return inner_a
def decortor_b(fun): 第二个装饰器
def inner_b(*args,**kwargs):
print('get in inner_b')
return fun(*args,**kwargs)
return inner_b
@decorator_a 先调用那个装饰器,那个就先运行
@decortor_b
def f(x):
print('get in f')
return x*3
f(1)
@decortor_b
@decorator_a
def f(x):
print('get in f')
return x*3
f(1)
打印结果
get in inner_a
get in inner_b
get in f
get in inner_b
get in inner_a
get in f