Python—裝飾器詳解

裝飾器:(語法糖)python

本質是函數,它是賦予函數新功能,可是不改變函數的源代碼及調用方式
 
原則:
1.不能修改被裝飾函數的源代碼
2.不能修改被裝飾函數的調用方式
3.函數的返回值也不變
這兩點簡而言之,就是裝飾器對被裝飾函數來講是透明的
 
知識儲備
1.函數即變量
     好比定義了一個變量  x = ‘gkx’   python是一門解釋性語言,解釋了‘gkx’,並給它分配了內存地址,而 x 就是這個內存地址的一個索引,相似門牌號。
同理可得 def test():print('gkx') 定義了一個函數  test是它的門牌號,print('gkx')分配了一個內存地址。故能夠理解爲函數即變量。
2.高階函數
    a.把一個函數名看成實參傳遞給另一個函數(在不改變函數源代碼的狀況
爲其添加新功能)
    b.返回值中包含函數名(不改變函數調用方式
3.嵌套函數
1 嵌套函數  在一個函數的函數體內,用def聲明一個新函數
2 def foo():
3     print('in the foo.')
4     def bar():
5         print('in the bar.')
6     bar()        #要調用bar須要在在函數體內調用,相似局部變量
7 foo()

 

裝飾器例子:僅針對註釋的幾段,對其進行排序,以下紅字app

 1 import time       #python的debug都是先讀取最外層框架(最外層沒有縮進),最外層中若是涉及到調用,再接着運行調用內容。  第一步
 2                                     
 3 def timer(func): #當讀取到 @timer的時候,至關於運行 test1 = timer(test1),因此會返回來讀取 warpper  第三步  4     def warpper(*args,**kwargs):
 5         start_time = time.time()
 6         func(*args,**kwargs)  #此時纔是真正意義上運行 test1函數 第六步
       return func(*args,**kwargs) #保證fun()返回值也不變
7 stop_time = time.time() 8 print('in the test1() %s'%(stop_time-start_time)) 9 return warpper #把test1看成實參傳遞給 timer,timer(test1),此時返回的是 函數warpper的內存地址 第四步 10 11 #而後此時運行到 python裏的語法【@timer】 12 @timer #至關於 test1 = timer(test1),返回warpper的內存地址,此時若是運行 test1(),至關於 warpper(),warpper就開始執行其函數體內的語句 第二步 13 def test1(): 14 time.sleep(1) 15 print('in the test1')
    return ‘from test1’
16 test1() #此時運行的 test1()已經不是直接運行 test1函數了,是通過@timer,轉換成運行 warpper()了 第五步

 

 

 裝飾器進階版,裝飾器自己帶參數框架

 1 user = 'gkx'
 2 pass_1 = '123'
 3 def decorator(auth_type):
 4     print("auth type",auth_type)
 5     def outer_warpper(func):
 6         def warpper(*args,**kwargs):
 7             if auth_type == 'local':
 8                 username = input("id")
 9                 password = input("password")
10                 if username == user and password == pass_1:
11                     print('\033[32;1mwelcome\033[0m')
12                     res = func(*args,**kwargs)
13                     print("after decorator")
14                     return res
15                 else:
16                     print('\033[31;1mwrong info\033[0m')
17             elif auth_type == 'ldap':
18                 print('我不會')
19         return  warpper
20     return outer_warpper    #當訪問到這裏的返回值時候,會繼續執行 warpper,而後執行邏輯就和上面提到的timer同樣了
21 
22 
23 
24 @decorator(auth_type='local')  #這裏分紅兩部分看,第一部分是 調用decorator(auth_type = 'local'),此時返回outer_wrapper的內存地址
                    #在第一部分的基礎上,此時加上@,變成了 @outer_wrapper,至關於 homepage = outer_wrapper(wrapper),再返回了wrapper的內存地址

25 def homepage():
26   print('home page')
27   return 'from home'

29 @decorator(auth_type='ldap') 30 def bbs(): 31 print('in bbs') 32 33 print(homepage()) 34 bbs()

 

裝飾器三個重要補充:ide

#一共有三個

# 第一個
from functools import wraps

def outer(func):
    @wraps(func)    #wraps模塊
    def inner(*args,**kwargs):
        print('裝飾前')
        ret = func(*args,**kwargs)
        print('裝飾後')
        return ret
    return inner

@outer
def holiday(day):
    '''

    :param day: days of vacation
    :return:
    '''
    print("放假%s"%day)
    return '好開心'

print(holiday.__name__)   #import wraps後此時打印holiday函數名,不然是 inner函數名
print(holiday.__doc__)
ret = holiday(3)
print(ret)

# 第二個,當裝飾器帶參數
import time
FLAG = False
def out_timmer(flag):
    def timmer(func):
        def inner(*args,**kwargs):
            if flag:
                start = time.time()
                ret = func()
                end = time.time()
                print(start-end)
                return ret
            else:
                ret = func()
                return ret
        return inner
    return timmer
@out_timmer(FLAG)   #能夠當作兩部 1,  timmer = out_timmer(FLAG)     2,  @timmer
def shop1():
    time.sleep(0.01)
    print('buy first thing')

@out_timmer(FLAG)
def shop2():
    time.sleep(0.01)
    print('buy second thing')

shop1()
shop2()


#第三個    函數被多個裝飾器調用
def wrapper1(func):  #func-----> f
    def inner1():
        print('wrapper1,befor func')
        ret = func()
        print('wrapper1,after func')   #這一句運行完,可是inner2還沒結束,要返回inner2繼續運行【print('wrapper2,after func')】
        return ret
    return inner1

def wrapper2(func):   #func-----> inner1  inner1傳給了wrapper2
    def inner2():
        print('wrapper2,befor func')  #運行完這一句,下一句運行inner1,故返回到wrapper1繼續運行
        ret = func()           #inner1
        print('wrapper2,after func')
        return ret
    return inner2

@wrapper2          #wrapper1 執行完後,執行wrapper2   可是此時傳入的不是f,是 inner1,至關於  wrapper(inner1)  == inner2 而後繼續運行warpper2
@wrapper1          #先執行到這裏,由於語法糖要找離它最近的函數。wrapper2沒找到,故往下運行。此時函數 f傳給wrapper1   至關於  f = wrapper1(f)  即爲 inner1
def f():
    print('in the f')
f()          #--------->>調用inner2
View Code
相關文章
相關標籤/搜索