经典装饰器代码解析

代码:

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…'这个字符串。

猜你喜欢

转载自blog.csdn.net/washing1127/article/details/83449828