一、装饰器实现
比如程序中有个原本的功能函数,打印func,返回value
def func():
print("func")
value = (1, 2, 3, 4)
return value
新需求:要将在输出fun之前,打印before,之后打印after
1、方式一
方式一:修改功能函数内部代码实现
def func():
# 新增功能
print("before")
print("func")
value = (1, 2, 3, 4)
# 新增功能
print("after")
return value
2、方式二
方式一很容易实现。如果使用装饰器,如方式二。
方式二:装饰器实现功能
def func():
print("func")
value = (1, 2, 3, 4)
return value
def outer(origin):
def inner():
# 新增功能
print("before")
res = origin()
# 新增功能
print("after")
return res
return inner
func = outer(func)
res = func()
在装饰器实现方式中,将func函数对象作为参数传入outer函数,然后inner函数中调用原func函数之外增加额外需求的功能。func=outer(func)
二、装饰器改进
上述方式二中func = outer(func)
用来表示用outer
修饰func
,python提供一种更加灵活的装饰方式。
利用python支持的特殊语法
@decorator
def func():
pass
func()
内部会自动执行 func=decorator(func)
也就是调用func
相当于调用decorator(func)
1、方式三
根据语法修改上述方式二装饰器变为方式三:
def outer(origin):
def inner():
print("before")
res = origin()
print("after")
return res
return inner
# 注意装饰器与被装饰函数代码中的顺序
@outer
def func():
print("func")
value = [1, 2, 3]
return value
res = func()
可以看到方式一实现简单,要修改源代码,不符合代码习惯。方式二实现复杂,可读性差了一些,但是方式二的优势体现在扩展性更高,如下。
def outer(origin):
def inner():
print("before")
res = origin()
print("after")
return res
return inner
@outer
def func1():
print("func1")
value = [1, 2, 3]
return value
@outer
def func2():
print("func2")
value = [1, 2, 3]
return value
@outer
def func3():
print("func3")
value = [1, 2, 3]
return value
res1 = func1()
res2 = func2()
res3 = func3()
如上,当有多个需要被装饰的函数时候,可以直接调用装饰器装饰,而不需要像方式一一样逐个修改功能函数,不容易出错,更加灵活,代码更加健壮。
2、方式四
但是方式三的问题在于,如果加入各个func函数都需要传参,并且参数类型,参数个数不同的时候,装饰器就无法统一接收,出现问题。因此可以使用可变参数优化函数器,使其支持接收任意函数参数。如方式四
方式四:优化装饰器
def outer(origin):
def inner(*args, **kwargs):
print("before")
res = origin(*args, **kwargs)
print("after")
return res
return inner
@outer
def func(a1): # func = outer(func)
print("func", a1)
value = [1, 2, 3]
return value
@outer
def func2(a1, a2):
print("func2", a1, a2)
value = [1, 2, 3]
return value
@outer
def func3():
print("func3")
value = [1, 2, 3]
return value
res = func(12)
res2 = func2(11, a2=100)
res3 = func3()
func1, func2, func3
参数个数不同,outer
装饰器也能够正常接收,并传递给真正的功能函数func1, func2, func3
。
传参:
- args, **kwargs用于编写可变长参数的函数,接收参数,args将接收的额外位置参数组成元组,**kwargs收集额外的关键字参数组成字典。
- 实际起作用的是
*与**
,args和kwargs只是作为约定好的规范名称。
三、总结
1、decorator
Py中装饰器原理:基于@语法糖和函数闭包,将原函数封装在闭包中执行。
实现效果:可以在不改变函数内部代码以及调用方式的前提下,实现功能扩展
使用场景:多个函数系统统一执行前后需要自定义功能
示例
def outer(origin):
def inner(*arg, **kwarg):
# 执行前
res = origin(*arg, **kwarg)
# 执行后
return res
return inner
def func()
pass
func()
2、场景
真正的业务场景中,如网站应用的很多操作,比如电商网站浏览商品页面添加购物车,博客页面点赞评论,这些操作都需要用户登录之后才能进行。真正的业务应该是用户将商品添加购物车,点赞评论,而额外的需求是要先判断是否登录,这部分额外的需求就用一个单独的装饰器来做。一旦涉及到判断用户登录状态的逻辑都可以调用这个装饰器。
Django伪码示例:
# 登录装饰器
def login(func):
def login_fun(request, *args, **kwargs):
""" 登录装饰器:如果用户已经登录,则正常执行,如果用户未登录,则跳转登录页面"""
if 用户id in 登录用户列表:
return func(request, *args, **kwargs)
else:
# 未登录重定向回登录页面
red = HttpResponseRedirect(登录页面)
return red
return login_fun
@login
def order(request):
"""订单路由函数,执行具体查看订单并返回逻辑"""
pass
如上,在处理订单之前先检测一下先用装饰器检查用户是否登录。如果用户已经登录则直接进入订单路由函数,如果没有登录,则返回登录页面先登录再查询用户的订单。
注:以上仅为学习记录笔记,如果错误或者相同,轻喷,蟹蟹蟹蟹