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'

  

原文地址:https://www.cnblogs.com/xxby/p/5565671.html