1. 程式人生 > >經典裝飾器程式碼解析

經典裝飾器程式碼解析

程式碼:

def A(funC):
    def B(funE):
        def C(*args, **kwargs):
            out = funC(funE)(*args,**kwargs)
            return out + "...111..."
        return C
    return B
@A
def C(funE):
    def decorated_E_by_C(str):
        return funE(str) + "。。。222。。。"
    return decorated_E_by_C
@C
def
E(str): return str print(E("A string is"))

執行結果:

A string is。。。222。。。...111...

程式執行步驟:

  1. 定義A函式,假設開闢記憶體空間為0x11
  2. 定義C函式,假設開闢記憶體空間為0x33
  3. 因為C上有A的裝飾器,所以相當於在定義C後運行了C = A©,所以這個時候要呼叫A函式 ,並把C的函式名,即0x33這個地址傳給了funC
  4. A函式的呼叫結果是定義了一個B函式,假設開闢記憶體空間為0x22,並把0x22的地址返回給了C這個函式名。此後C相當於指向0x22的函式
  5. 定義函式E,假設開闢記憶體空間為0x55
  6. 因為E上有C的裝飾器,所以相當於在定義E後運行了E = C(E),所以這個時候要呼叫C函式 ,並把E的函式名,即0x55這個地址傳給了funE
  7. 由於C已經指向了0x22,所以呼叫C函式的結果是定義了一個在A函式內部的C函式,這個C和外邊的C不同,可稱之為C2.假設C2的記憶體空間地址為0x44,並把0x44這個地址返回給了E這個函式名。此後E相當於指向0x44的函式
  8. 最後呼叫E函式,傳入引數為字串‘A string is’。也就是呼叫了0x44的原來的C2的函式,把‘A string is’傳給了(*args, **kwargs)
  9. 在0x44中,先呼叫了funC函式,其引數是funE。funC指向的是0x33,即最早的C函式。在這個函式中,定義了一個decorated_E_by_C的函式,假設其地址為0x53.建立後,把這個地址返回給了funC(funE)這個整體。所以說funC(funE)就相當於位置在0x53的函式名,後面加括號相當於呼叫這個函式,傳入‘A string is’引數。
  10. 呼叫0x53處的函式,要返回funE(‘A string is’),加。。。222。。。
  11. funE直接返回原來的字串‘A string is’,所以0x53最終會返回‘A string is。。。222。。。’ 給了out
  12. 程式往下執行,返回out+…111…即‘A string is。。。222。。。…111…'給了0x44的函式,也就是E函式。
  13. 所以最終打印出來‘A string is。。。222。。。…111…'這個字串。