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

为装饰器内函数传递动态参数:

 

 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
View Code

 

为装饰器传递参数:

创建一个装饰器框架,接收不同的参数,来调用不同的函数,实现不同的装饰器。

初始代码:

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

  现在需要创建一个装饰器,接收不同的参数,来调用不同的函数,实现不同的功能。

 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
View Code

 代码执行逻辑:

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)



 

 

 

  

 

posted @ 2020-02-06 23:04  Mr_Resin  阅读(117)  评论(0编辑  收藏  举报