python 裝飾器

裝飾器

裝飾器做用:裝飾器能夠在不改變函數體和函數調用的狀況下在該函數執行以前,或者執行以後進行額外的操做python

 

裝飾器功能:1.自動執行裝飾器函數並將其下面的函數名看成參數傳遞小程序

      2.將裝飾器函數的返回值,賦值給被裝飾器函數app

被裝飾器無返回值

def outer(func):
    def inner():
        print('before')
        func()
        print('after')
    return inner

@outer
def f1():
    print('F1'.center(10,'-'))
f1()

執行結果:函數

before
----F1----
after

解析:spa

1.自動執行outer函數,並將下面的函數名f1看成參數傳遞code

2.將outer函數的返回值,從新賦值給f1,outer的返回值就是inner()函數體,而func() == 老f1(),blog

此時,新的f1()就是內存

print('before')utf-8

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

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'
相關文章
相關標籤/搜索