1. 程式人生 > 其它 >記憶碎片之python裝飾器及多個裝飾器聯合使用

記憶碎片之python裝飾器及多個裝飾器聯合使用

技術標籤:經驗分享python裝飾器裝飾器進階裝飾器心得裝飾器用法

import functools


def outer(func):
    functools.wraps(func)  # inner.__name__ = func.__name__  inner.__doc__ = func.__doc__  偽裝的更像主函式而已

    def inner(*args, **kwargs):  # 如果func()有引數,那裝飾器之後func就等價於inner函式,所以也需要引數接收
        print("原函式執行前的任務")  # 當然也可以直接形象接受引數,前提是你知道原函式的引數,如inner(a,b=1,*args, **kwargs)
if False: res = func(*args, **kwargs) # 這裡是真正呼叫原函式,原函式如果有引數,這裡肯定也得有引數啊,這裡的引數從inner引數獲取 return res else: print("原函式執行後的任務") print("反向解析跳轉登陸介面") return inner @outer def func(a, b=1): print("進入個人詳情頁"
) # func("a", 2) # 裝飾器說明: # 對於裝飾器有一點必須要說明,不然很難理解,就是函式名是否加括號的問題 # 函式加括號表示對函式的呼叫 # 函式不加括號表示引用,可以理解成一個變數,指向函式程式碼所在的地址 # 如果上面兩行不明白的,會直接在下面兩句中迷茫,這也是我原來學裝飾器迷茫的地方,(迷茫:一個func被賦值,然後func()就裝飾器或閉包生效了) # func新增裝飾器之後 相當於是func = outer(func) 此時函式func相當於一個變數,指向outer(func)函式 # 然而 outer(func) return返回的是inner函式 return 後面的函式是不加括號的,表示引用inner函式
# 所以在執行 func函式的時候,實際上執行的是inner函式 inner函式返回原函式的值,所以在拿該值的時候會執行原來的func函式 # 在inner函式中對原函式func做了功能擴充套件 比如做是否登陸的判斷 如果登陸了執行inner裡面的return res實際上是呼叫原函式,比如打開個人詳情頁 # 執行程式,修改if判斷的結果,檢視裝飾器執行的結果 # 當理解了上面的單個裝飾器的時候再理解多個裝飾器,面試題很囂張的 def outer1(func): functools.wraps(func) # inner.__name__ = func.__name__ inner.__doc__ = func.__doc__ 偽裝的更像主函式而已 def inner1(*args, **kwargs): # 如果func()有引數,那裝飾器之後func就等價於inner函式,所以也需要引數接收 print("原函式執行前的任務1") # 當然也可以直接形象接受引數,前提是你知道原函式的引數,如inner(a,b=1,*args, **kwargs) if True: res = func(*args, **kwargs) # 這裡是真正呼叫原函式,原函式如果有引數,這裡肯定也得有引數啊,這裡的引數從inner引數獲取 return res else: print("原函式執行後的任務1") print("反向解析跳轉登陸介面1") return inner1 def outer2(func): functools.wraps(func) # inner.__name__ = func.__name__ inner.__doc__ = func.__doc__ 偽裝的更像主函式而已 def inner2(*args, **kwargs): # 如果func()有引數,那裝飾器之後func就等價於inner函式,所以也需要引數接收 print("原函式執行前的任務2") # 當然也可以直接形象接受引數,前提是你知道原函式的引數,如inner(a,b=1,*args, **kwargs) if True: res = func(*args, **kwargs) # 這裡是真正呼叫原函式,原函式如果有引數,這裡肯定也得有引數啊,這裡的引數從inner引數獲取 return res else: print("原函式執行後的任務2") print("反向解析跳轉登陸介面2") return inner2 @outer1 @outer2 def func_s(a, b=1): print("進入個人詳情頁") func_s("a", 2) # 下面按照if的判斷來做多個裝飾的分析 # 首先要明白兩個裝飾器的閉包形式 # func_s = outer1(outer2(func_s)) # 一句話:括號裡面的函式是括號外面的引數也是其內部的func(*args, **kwargs)原函式 # func_s("a", 2) # 首先看出裝飾器是從上向下執行的,先進入到outer1裡面,經過判斷之後執行裡面的inner1函式,判斷是否進入res = func(*args, **kwargs) # 在執行outer1時,實際上執行的是inner1閉包函式,最上面說到 func = outer(func)等價於把outer的inner賦值給了func,並且在inner中擴充套件了功能和判斷是否呼叫原函式func # 所以outer1裡面這個res = func(*args, **kwargs)是誰呢?他就是outer2(func_s),因為他就是outer1的引數,也是他的原函式,是對outer2的功能擴充套件 # 在呼叫outer2(func_s)的時候,就是func_s = inner2了,在inner2中對func_s做了功能擴充套件和判斷是否呼叫原函式func_s # True True # 呼叫outer1裝飾器,判斷為真,呼叫res = func(*args, **kwargs)。進入outer2,outer2為真,呼叫func_s """ 原函式執行前的任務1 原函式執行前的任務2 進入個人詳情頁 """ # True False # 呼叫outer1裝飾器,判斷為真,呼叫res = func(*args, **kwargs)。進入outer2,outer2為假,不呼叫func_s """ 原函式執行前的任務1 原函式執行前的任務2 原函式執行後的任務2 反向解析跳轉登陸介面2 """ # False True # 呼叫outer1裝飾器,判斷為假,不呼叫res = func(*args, **kwargs)。不進入outer2,不呼叫func_s """ 原函式執行前的任務1 原函式執行後的任務1 反向解析跳轉登陸介面1 """ # False False # 呼叫outer1裝飾器,判斷為假,不呼叫res = func(*args, **kwargs)。不進入outer2,不呼叫func_s """ 原函式執行前的任務1 原函式執行後的任務1 反向解析跳轉登陸介面1 """