zoukankan      html  css  js  c++  java
  • python 装饰器

    装饰器

    装饰器作用:装饰器可以在不改变函数体和函数调用的情况下在该函数执行之前,或者执行之后进行额外的操作

    装饰器功能:1.自动执行装饰器函数并将其下面的函数名当作参数传递

          2.将装饰器函数的返回值,赋值给被装饰器函数

    被装饰器无返回值

    def outer(func):
        def inner():
            print('before')
            func()
            print('after')
        return inner
    
    @outer
    def f1():
        print('F1'.center(10,'-'))
    f1()

    执行结果:

    before
    ----F1----
    after

    解析:

    1.自动执行outer函数,并将下面的函数名f1当作参数传递

    2.将outer函数的返回值,重新赋值给f1,outer的返回值就是inner()函数体,而func() == 老f1(),

    此时,新的f1()就是

    print('before')

    print('F1'.center(10,'-'))

    print('after')

    被装饰器有返回值

    def outer(func):
        def inner():
            print('before')
            res = func()return res
        return inner
    
    @outer
    def f1():
        return 'F1....'
    
    a = f1()
    print(a)

    执行结果:

    before
    F1....

    解析:

    当函数有返回值时,同样inner()方法就相当于f1(),也就是说inner()函数的返回值就是老f1()的返回值。inner()函数的返回值就是res,也就是老f1()的返回值。

    被装饰器有参数

    dict_a = {'aa':123}
    str_a = 'abc'
    list_a = [1,2]
    
    def outer(func):
        def inner(*args,**kwargs):
            print('before')
            res = func(*args,**kwargs)
            return res
        return inner
    
    @outer
    def f1(*args,**kwargs):
        print(*args,**kwargs)
        return 'F1....'
    
    a = f1(str_a,list_a,dict_a)
    print(a)

    执行结果:

    before
    abc [1, 2] {'aa': 123}
    F1....

    解析:

    当被装饰的函数有参数时,装饰器函数的内层函数就相当于被装饰的函数。f1()函数就相当于inner()函数,因为f1()在调用时有参数,所以需要在inner()函数增加参数,大多数情况可以写成inner(*args,**kwargs)万能参数的形式。

    双层装饰器

    目前有一个小小的需求,写一个小程序,要求用户登录后可以查看home目录,管理员可以查看所有目录,不登录不可以查看

    代码如下:

    USER_INFO ={}
    
    def check_login(func):                 #验证登录装饰器
        def inner(*args,**kwargs):
            if USER_INFO.get('islogin',None):
                ret = func(*args,**kwargs)
                return ret
            else:
                print('请登录')
        return inner
    
    def check_admin(func):                 #验证admin装饰器
        def inner(*args,**kwargs):
            if USER_INFO.get('islogin',None):
                if USER_INFO.get('usertype',None) ==2:
                    ret =func(*args,**kwargs)
                    return ret
                else:
                    print('无权查看')
            else:
                print('请登录')
        return inner
    
    def login():
        user = input('please input your name:')
        if user == 'admin':
            USER_INFO['islogin']=True
            USER_INFO['usertype']=2
        else:
            USER_INFO['islogin']=True
            USER_INFO['usertype']=1
    
    @check_login
    def home():
        print('home')
    @check_admin
    def index():
        print('index')
    def main():
        while True:
            inp = input('1.login 2.home 3.index  \n>>>')
            if inp == '1':
                login()
            elif inp =='2':
                home()
            elif inp == '3' :
                index()
    main()

    执行结果:

    1.login 2.home 3.index
    >>>2
    请登录
    1.login 2.home 3.index
    >>>3
    请登录
    1.login 2.home 3.index
    >>>1
    please input your name:xx      #xx登录
    1.login 2.home 3.index
    >>>2                   #xx查看home目录
    home
    1.login 2.home 3.index
    >>>3
    无权查看
    1.login 2.home 3.index
    >>>1
    please input your name:admin    #admin登录
    1.login 2.home 3.index
    >>>2                   #admin查看home目录
    home
    1.login 2.home 3.index
    >>>3                   #admin查看index目录
    index
    1.login 2.home 3.index
    >>>

    分析:这样做虽然功能可以实现,但是如果要是还有超级管理员或者其他更高权限的用户,还需写更多的装饰器,比较麻烦,代码重用性太高

    所以需要用多层装饰器做权限验证

    代码如下:

    USER_INFO ={}
    
    def check_login(func):
        def inner(*args,**kwargs):
            if USER_INFO.get('islogin',None):          #1
                ret = func(*args,**kwargs)            #2
                return ret                      #7
            else:
                print('请登录')
        return inner
    
    def check_admin(func):
        def inner(*args,**kwargs):
            if USER_INFO.get('usertype',None) ==2:       #3
                ret =func(*args,**kwargs)             #4
                return ret                      #6
            else:
                print('无权查看')
        return inner
    
    def login():
        user = input('please input your name:')
        if user == 'admin':
            USER_INFO['islogin']=True
            USER_INFO['usertype']=2
        else:
            USER_INFO['islogin']=True
            USER_INFO['usertype']=1
    
    @check_login
    def home():
        print('home')
    
    @check_login
    @check_admin
    def index():                            #5
        print('index')
    def main():
        while True:
            inp = input('1.login 2.home 3.index  \n>>>')
            if inp == '1':
                login()
            elif inp =='2':
                home()
            elif inp == '3' :
                index()
    main()

    分析这段代码:

    def check_login(func):
        def inner(*args,**kwargs):
            if USER_INFO.get('islogin',None):       #1
                ret = func(*args,**kwargs)          #2
                return ret                          #7
            else:
                print('请登录')
        return inner
    
    def check_admin(func):
        def inner(*args,**kwargs):
            if USER_INFO.get('usertype',None) ==2:  #3
                ret =func(*args,**kwargs)           #4
                return ret                          #6
            else:
                print('无权查看')
        return inner
    
    @check_login
    @check_admin
    def index():                                    #5
        print('index')

    首先,解释器会先把check_login和check_admin这两个函数加载到内存

    然后先解释@check_admin/def index():   会把它们俩作为一个整体去解释,并定义为new_index函数,其实就是check_admin里的inner函数,index函数就是check_admin里的func函数

    此时,解释器会继续解释@check_login/new_index    会把它们作为一个整体去解释,并定义为new_new_index函数,其实就是check_login里的inner函数,new_index函数就是check_login里的func函数

    此时,最外层函数就是new_new_index函数,也就是check_login里的inner函数

    解释器从下往上解释完后,会从上往下执行函数,先从check_login里的inner函数执行

    1.先执行    if USER_INFO.get('islogin',None):          #1             ---》条件不满足直接print('请登录')

    2.       ret = func(*args,**kwargs)              #2

    3.     USER_INFO.get('usertype',None) ==2:  #3               ---》条件不满足直接print('无权查看')

    4.     ret =func(*args,**kwargs)        #4

    5.     def index():               #5

    6.     return ret                #6

    7.         return ret                 #7

    图文分析:

    更牛的装饰器

    #!/usr/bin/env python
    #coding:utf-8
      
    def Before(request,kargs):
        print 'before'
          
    def After(request,kargs):
        print 'after'
      
      
    def Filter(before_func,after_func):
        def outer(main_func):
            def wrapper(request,kargs):
                  
                before_result = before_func(request,kargs)
                if(before_result != None):
                    return before_result;
                  
                main_result = main_func(request,kargs)
                if(main_result != None):
                    return main_result;
                  
                after_result = after_func(request,kargs)
                if(after_result != None):
                    return after_result;
                  
            return wrapper
        return outer
          
    @Filter(Before, After)
    def Index(request,kargs):
        print 'index'

      

  • 相关阅读:
    [leetcode] 135. Candy (hard)
    [leetcode] 134. Gas Station (medium)
    [OpenGL] 绘制并且判断凹凸多边形、自相交多边形。
    [leetcode] 45. Jump Game II(hard)
    [leetcode] 55. Jump Game (Medium)
    [leetcode] 392. Is Subsequence (Medium)
    [leetcode] 147. Insertion Sort List (Medium)
    [leetcode]914. X of a Kind in a Deck of Cards (easy)
    [leetcode] 234. Palindrome Linked List (easy)
    [leetcode] 290. Word Pattern (easy)
  • 原文地址:https://www.cnblogs.com/xxby/p/5565671.html
Copyright © 2011-2022 走看看