python笔记 装饰器运行步骤

108 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情

0 环境

  • 编辑器:idea或vscode
  • 系统版本:windows10
  • python版本:3.9.6

1 前言

一开始的时候我也想不明白装饰器,里面涉及到的闭包,让人头大,然后遇到js里的闭包,从某种层度来说,它是一种共识,那我们有必要去调试一下,证明我来过了。

2 调试

如下面的代码,我们只要记住入参函数,返回值函数就行啦,目的就是这里的add怎么被调用的,其他的两个打印结果可以先忽略。

def logger(fn):
    def wrap(*args, **kwargs):
        print("call {}".format(fn.__name__))
        ret = fn(*args, **kwargs)
        print("{} called".format(fn.__name__))
        return ret
    return wrap

if __name__ == '__main__':
    add = lambda x, y : x + y
    logged_add = logger(add)
    print("logged_add -->", logged_add)
    print(logged_add(2, 12))

首先我定义了一个匿名函数,它的使命就是两值相加得到的和返回,并且赋值给add变量,然后作为logger函数的入参传入(入参是函数),现在进入logger函数中看看。

先是指向的wrap函数。 image.png

当我在下一步,它不是执行wrap内部的函数,而是跳掉了return wrap这行代码了,这里wrap:.xxx.wrap at 0x....D0。这里先记下来,下面会用到的。 image.png

看到没,当指向return wrap这行代码的时候,我在点下一步,就会将这里的wrap函数返回值返回给定义的logged_add变量,有种生成器的味道,它还保存在那里,任我们使用,fn相加后面也是要用到的,是不是fn也是被保存的呢,答案不用说呀,就观察wrap函数里是存在fn函数的调用,答案呼之欲出,不管是否相信的,可以继续往下看。 image.png

最关键点说完了,下面就不用调试了,我直接调用wrap函数,这里2和12两个变量,wrap函数里的*args接收了了这两个参数,这里的fn就是那个两值相加的匿名函数。

image.png

当我执行到fn(*args, xxx),在继续下一步,机会跳转相加的匿名函数,然后继续下一步到打印,在下一步执行ret值的返回,得到最终的相加和14。