Python装饰器代码中wrapper.count逻辑及闭包关联疑问
解析这段Python装饰器计数代码
先过一遍代码的完整执行逻辑:
- 当Python加载到
@counter装饰foo时,会自动调用counter(foo)。 - 在
counter内部,先定义嵌套的wrapper函数,接着给wrapper这个函数对象添加count属性并初始化为0,最后返回wrapper。 - 此时原来的
foo变量已经被替换成了这个wrapper函数——也就是说,之后调用foo()本质是调用wrapper。
关于wrapper.count = 0的作用
这行是给返回的wrapper函数对象初始化计数器。Python里函数是一等对象,可以像普通对象一样绑定自定义属性。如果没有这行,第一次调用wrapper时执行wrapper.count += 1会直接报错——因为+=是先读取属性再赋值,读取阶段找不到count属性就会抛出AttributeError。
为什么调用两次后count不会重置为0
因为counter函数只会被执行一次:就是在装饰foo的那个时刻。wrapper.count = 0是在counter内部执行的,所以只会给wrapper初始化一次计数器。之后每次调用foo()(也就是调用wrapper),都是在同一个wrapper对象上累加count属性的值,不会重新触发counter的执行,自然也就不会重置count为0。
和闭包的关系
首先,wrapper本身是一个闭包——因为它引用了外部函数counter中的变量func(调用func(*args, **kwargs)时用到了这个外部变量)。但这段代码的计数逻辑并没有用到闭包变量:计数器是存在wrapper函数自身的属性上,而非counter函数的局部变量中(如果用闭包变量实现计数,会是另一种写法)。简单说,wrapper是闭包,但计数功能的实现和闭包无关。
内容的提问来源于stack exchange,提问作者May Pan
相关产品推荐
相关产品推荐

