048 装饰器
装饰器
- 器:只的就是工具
- 函数:也可以说是一个工具,需要用到这个工具的时候可以直接拿过来用
- 装饰器:是指对一个工具有装饰的作用,也就是说可以为一个工具添加其他的功能作用
- 所以定义装饰器其实就是相当于在定义一个函数,只不过这个函数的功能是用来为其他函数添加额外的功能
- 装饰器相当于一个函数A,它用来装饰另一个函数B,为函数B添加其他的功能,这就是用一个函数A去装饰另一个函数B
一、无参装饰器
1.为什么要使用装饰器
- 就好比我们已经完成了一个项目,但是我们需要修改其中某个方法,但是我们又不想修改他原来的
调用方法,那这个时候我们就可以使用装饰器来实现修改
- 使用装饰器的时候我们需要遵循两点原则
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
2.改变源代码方式修改函数的功能
# 原函数
def name():
print('hello xichen')
name
# 为原函数增加功能
# 修改源代码的方式
def name():
print('---------')
print('hello xichen')
print('---------')
name()
3.修改调用方式
import time
def index():
print('welcome to index')
time.sleep(1)
def func(func):
start = time.time()
fun()
end = time.time()
print(start-end)
func(index)
4.用装饰器来修改
# 没有返回值的
import time
def index():
print('welcome to index')
time.sleep(1)
def func(fun):
def f():# 重新创建的index
start = time.time()
fun() # 真正的index
end = time.time()
print(start-end)
return f
index = func(index) # index = func(),其实就是等于f()
index()
# 有返回值的
import time
def index():
print('welcome to index')
time.sleep(1)
return 123
def func(fun):
def f():# 重新创建的index
start = time.time()
res = fun() # 真正的index
end = time.time()
print(start-end)
return res
return f
index = func(index) # index = fun,其实就是等于f()
res = index()
print(res)
5.完善的装饰器
- 如果原始的index()有返回值的时候,那么我们用装饰器为其添加的功能的最后返回值也应该和原函数的返回值相同
- 所以这个时候我们就可以哪一个变量来接收装饰器最后的值并且返回
- 也就是说我们需要同步原始的函数返回值和我们后来新建的一个添加功能的函数的返回值
import time
def func(fun):
def f():
start = time.time()
res = fun()
end = time.time()
print(end - start)
return res
return f
def index():
print('hello xichen')
time.sleep(1)
return 123
index = func(index)
res = index()
print(res)
- 如果原始的index()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有后来新建的添加功能的函数就是=index(),所以给后来新建的函数方法传参即可。
import time
def func(fun):
def f1(*args, **kwargs):
print('args:', args)
print('kwargs:', kwargs)
start = time.time()
res = fun(*args, **kwargs)
end = time.time()
print(end - start)
return res
return f1
@func
def index(a,b=1):
print('a:', a)
print('b', b)
print('hello xichen')
time.sleep(1)
return 123
res = index(1)
print(res)
6.装饰器语法糖
- 在被装饰函数正上方,并且是单独一行写上
@装饰器名
- 用语法糖的话会更精简代码,而且日后我们用的装饰器都是已经定义好的,可以直接拿过来用
import time
def func(fun):
def f(*args, **kwargs):
print('args:', args)
print('kwargs:', kwargs)
start = time.time()
res = fun(*args, **kwargs)
end = time.time()
print(end - start)
return res
return f
@func
def index(a,b=1):
print('a:', a)
print('b', b)
print('hello xichen')
time.sleep(1)
return 123
res = index(1)
print(res)
7.装饰器模板
- 我们只要记住了装饰器的模板,其实就等于已经会了如何去用装饰器了
def func(fun):
def f(*args,**kwargs):
res = fun(*args,**kwargs)
# 给原来的函数加功能
return res
return f
二、有参的装饰器
1.有参的三层装饰器
def data(enter):
def func(fun):
def f(*args,**kwargs):
if enter == 'file':
uname = input('uname:')
upwd = input('upwd:')
if uname == 'xichen' and upwd == '123':
print('登陆成功')
res = fun(*args,**kwargs)
return res
else:
print('登录失败')
else:
print('数据来源数据库,不可用')
return f
return func
@data('file')
def shopping():
print('欢迎shopping')
return 123
res = shopping()
print(res)
2.双层装饰器
def demo2(func2):
def add_func2(*args,**kwargs):
print('-------------')
func2(*args,**kwargs) # func2此时是demo1装饰的函数add,添加的功能的add_func1
print('-------------')
return func2
return add_func2
def demo1(func1):
def add_func(*args,**kwargs):
print('***********')
func1(*args,**kwargs) # func1是被demo装饰的函数add
print('***********')
return func1
return add_func
def add():
print('hello')
# 先运行的是先装饰的函数demo1
add = demo1(add) # add = func1,也就是在调用add_func1,add返回的是add_func1
add = demo2(add) # add = func2,也就是在调用add_func2,add返回的是add_func2
add()
3.双层装饰器模板
def demo2(fun2):
def add_func2(*args,**kwargs):
res = fun2(*args,**kwargs)
# 添加功能
return res
return add_fun2
def demo1(fun1):
def add_func1(*args,**kwargs):
res = fun1(*args,**kwargs)
# 添加功能
return res
return add_fun1
def add():
print('hello xichen')
return 123
add = demo1(add)
add = demo2(add)
add()
4.三层装饰器模板
def demo(enter):
def func(fun):
def f(*args,**kwargs)
# 添加功能
res = fun(*args,**kwargs)
return f
return func
@demo(参数---enter)
def add()
print('hello xichen')
return 123
res = add()
res()
- 由于两层的装饰器,参数必须得固定位
func
,但是三层的装饰器解除了这个限制。我们不仅仅可以使用单个参数的三层装饰器,多个参数的只需要在三层装饰器中多加入几个参数即可。也就是说装饰器三层即可,多加一层反倒无用。