携手创作,共同成长!这是我参与「掘金日新计划 · 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函数。
当我在下一步,它不是执行wrap内部的函数,而是跳掉了return wrap这行代码了,这里wrap:.xxx.wrap at 0x....D0。这里先记下来,下面会用到的。
看到没,当指向return wrap这行代码的时候,我在点下一步,就会将这里的wrap函数返回值返回给定义的logged_add变量,有种生成器的味道,它还保存在那里,任我们使用,fn相加后面也是要用到的,是不是fn也是被保存的呢,答案不用说呀,就观察wrap函数里是存在fn函数的调用,答案呼之欲出,不管是否相信的,可以继续往下看。
最关键点说完了,下面就不用调试了,我直接调用wrap函数,这里2和12两个变量,wrap函数里的*args接收了了这两个参数,这里的fn就是那个两值相加的匿名函数。
当我执行到fn(*args, xxx),在继续下一步,机会跳转相加的匿名函数,然后继续下一步到打印,在下一步执行ret值的返回,得到最终的相加和14。