比如程序中有个原本的功能函数,打印func,返回value
def func(): print("func") value = (1, 2, 3, 4) return value
新需求:要将在输出fun之前,打印before,之后打印after
方式一:修改功能函数内部代码实现
def func(): # 新增功能 print("before") print("func") value = (1, 2, 3, 4) # 新增功能 print("after") return value
方式一很容易实现。如果使用装饰器,如方式二。
方式二:装饰器实现功能
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)
根据语法修改上述方式二装饰器变为方式三:
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()
如上,当有多个需要被装饰的函数时候,可以直接调用装饰器装饰,而不需要像方式一一样逐个修改功能函数,不容易出错,更加灵活,代码更加健壮。
但是方式三的问题在于,如果加入各个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
。
Py中装饰器原理:基于@语法糖和函数闭包,将原函数封装在闭包中执行。
实现效果:可以在不改变函数内部代码以及调用方式的前提下,实现功能扩展
使用场景:多个函数系统统一执行前后需要自定义功能
示例
def outer(origin): def inner(*arg, **kwarg): # 执行前 res = origin(*arg, **kwarg) # 执行后 return res return inner def func() pass func()
真正的业务场景中,如网站应用的很多操作,比如电商网站浏览商品页面添加购物车,博客页面点赞评论,这些操作都需要用户登录之后才能进行。真正的业务应该是用户将商品添加购物车,点赞评论,而额外的需求是要先判断是否登录,这部分额外的需求就用一个单独的装饰器来做。一旦涉及到判断用户登录状态的逻辑都可以调用这个装饰器。
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
如上,在处理订单之前先检测一下先用装饰器检查用户是否登录。如果用户已经登录则直接进入订单路由函数,如果没有登录,则返回登录页面先登录再查询用户的订单。
注:以上仅为学习记录笔记,如果错误或者相同,轻喷,蟹蟹蟹蟹