python 装饰器
1、必备知识
#### 第一波 #### def func(arg): print(arg) func #表示函数名 func() #表示执行函数 #### 第二波 #### def func(arg): print(arg) func = lambda x:print(x) func() # 执行下面的lambda表达式,而不再是原来的func函数,因为函数func被重新定义了
2、需求模拟
想象一种场景,假定我们访问网站时(除了首页home之外),每一个页面都是一个单独的函数,现在有如下需求,要求不改变当前函数体本身的内容,和原有的函数调用方式的前提下,实现访问函数(页面)之前,都需要进行验证。
当前代码如下:
def home(name): print("Welcome [%s] to home page" % name) def tv(name): print("Welcome [%s] to TV page" % name) def movie(name): print("Welcome [%s] to movie page" % name) tv('jack')
代码修改如下:
def login(func): #func = tv print("passed user verification...") return func #tv def home(name): print("Welcome [%s] to home page" % name) def tv(name): print("Welcome [%s] to TV page" % name) def movie(name): print("Welcome [%s] to movie page" % name) tv = login(tv) tv('jack') passed user verification... Welcome [jack] to TV page
下面的代码效果和上面的功能是相同的:
def login(func): #func = tv print("passed user verification...") return func #tv def home(name): print("Welcome [%s] to home page" % name) @login def tv(name): print("Welcome [%s] to TV page" % name) def movie(name): print("Welcome [%s] to movie page" % name) # tv = login(tv) tv('jack') passed user verification... Welcome [jack] to TV page
代码的执行逻辑:
1. 执行tv = login(tv),调用执行login(func)函数,执行print("passed user verification...")和return func,此时的func为tv,则返回tv,执行的结果为,
passed user verification...
tv = tv
2. 执行tv('jack'),调用执行tv函数,Welcome [jack] to TV page
3.上述的在函数前加@login被称为装饰器,也被称为语法糖
4. 但是两段代码存在一个bug,不管是否执行tv(),都会预先执行print("passed user verification...")这段代码
代码改进:
def login(func): #func = tv def inner(args): print("passed user verification...") func(args) #tv return inner def home(name): print("Welcome [%s] to home page" % name) @login def tv(name): print("Welcome [%s] to TV page" % name) def movie(name): print("Welcome [%s] to movie page" % name) # tv = login(tv) tv('jack') passed user verification... Welcome [jack] to TV page
代码的执行逻辑:
1. 执行@login,相当于tv = login(tv),
2. 调用执行login(func)函数,return inner,那么此时tv被重新定义为tv = inner
3. 执行tv('jack'),调用执行inner(args)函数,执行print("passed user verification...")这段代码,之后执行func(args),即执行原始的tv(name)函数
Welcome [jack] to TV page
为装饰器内函数传递动态参数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def login(func): #func = tv 2 def inner(*args): 3 print("passed user verification...") 4 func(*args) #tv 5 return inner 6 7 def home(name): 8 print("Welcome [%s] to home page" % name) 9 10 @login 11 def tv(name,password): 12 print("Welcome [%s] to TV page" % name) 13 @login 14 def movie(name): 15 print("Welcome [%s] to movie page" % name) 16 17 # tv = login(tv) 18 tv('jack',123) 19 movie('jack') 20 21 passed user verification... 22 Welcome [jack] to TV page 23 passed user verification... 24 Welcome [jack] to movie page 25 26 27 def login(func): #func = tv 28 def inner(*args,**kwargs): 29 print("passed user verification...") 30 return func(*args,**kwargs) #tv 31 return inner 32 33 def home(name): 34 print("Welcome [%s] to home page" % name) 35 36 @login 37 def tv(name,password=123): 38 print("Welcome [%s] to TV page" % name) 39 return 4 40 @login 41 def movie(name): 42 print("Welcome [%s] to movie page" % name) 43 44 # tv = login(tv) 45 t=tv('jack',password=123) 46 print(t) 47 movie('jack') 48 49 passed user verification... 50 Welcome [jack] to TV page 51 4 52 passed user verification... 53 Welcome [jack] to movie page
为装饰器传递参数:
创建一个装饰器框架,接收不同的参数,来调用不同的函数,实现不同的装饰器。
初始代码:
def outer(main_func): #Index def wrapper(request,kargs): print('before') main_func(request,kargs) print('after') return wrapper @outer def Index(request,kargs): print('index') Index('hello','world') before index after
现在需要创建一个装饰器,接收不同的参数,来调用不同的函数,实现不同的功能。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def Before(request,kargs): 2 print('before') 3 4 def After(request,kargs): 5 print('after') 6 7 def Filter(before_func,after_func): 8 def outer(main_func): #Index 9 def wrapper(request,kargs): 10 before_func(request,kargs) 11 main_func(request,kargs) 12 after_func(request,kargs) 13 return wrapper 14 return outer 15 16 @Filter(Before,After) 17 def Index(request,kargs): 18 print('index') 19 Index('hello','world') 20 21 before 22 index 23 after
代码执行逻辑:
1.执行Filter(Before,After),传递参数Before和After,同时return outer
2.此时的@Filter(Before,After)变为了@outer
3.因为装饰器的作用是将装饰的函数作为它的参数,即outer(main_func)=outer(Index)
同时对函数重新赋值,此时执行outer函数
4.因为outer函数的返回时return wrapper,所以Index被重新赋值,Index=wrapper
5.此时执行Index('hello','world')=wrapper('hello','world')
6.执行wrapper('hello','world'),执行如下的代码
before_func(request,kargs)
main_func(request,kargs)
after_func(request,kargs)
其中,before_func和after_func为Filter()函数传递的参数替换
mian_func为outer()函数传递的参数替换,即为如下的代码内容
Before(request,kargs)
Index(request,kargs)
After(request,kargs)