Python闭包中total和count为何不是自由变量?如何设置?
关于Python闭包中自由变量的疑问
我正在阅读Luciano Ramalho所著的《Fluent Python》(个人认为这是一本很棒的书)。在装饰器与闭包章节中,有如下代码:
def make_averager(): series = [] def averager(value): series.append(value) total = sum(series) return total/len(series) return averager avg = make_averager()
在此例中,series是自由变量,可通过打印验证:
>>> avg.__code__.co_varnames ('new_value', 'total') >>> avg.__code__.co_freevars ('series',)
但当我重构make_averager()后:
def make_averager(): series = [] total = 0 count = 0 def averager(value): total += value count += 1 return total/count return averager avg = make_averager()
total和count并未被识别为自由变量,反而成为局部变量(avg.__code__.co_varnames返回('value', 'total', 'count'),avg.__code__.co_freevars返回())。series因未在averager中调用,不再是自由变量这点我能理解,但无法理解total和count的情况。请问为何它们不是自由变量,如何将它们设为自由变量?
问题解答
为什么total和count不是自由变量?
Python解释器对变量的赋值操作有明确判定规则:只要在函数内部对变量进行赋值(包括+=、-=这类增量赋值),就会默认该变量是当前函数的局部变量,即便外部嵌套作用域存在同名变量,也不会去引用外部的那个。
而第一个例子里的series.append(value)属于修改可变对象的操作,并没有对series本身赋值(没有改变series指向的内存地址),所以解释器会去外部作用域查找series,将其认定为自由变量。
如何将它们设为自由变量?
使用Python的nonlocal关键字,在内部函数averager中声明total和count来自外部嵌套作用域,这样解释器就不会将它们视为局部变量,而是标记为自由变量。
修改后的代码如下:
def make_averager(): series = [] total = 0 count = 0 def averager(value): nonlocal total, count total += value count += 1 return total/count return averager avg = make_averager()
此时再验证变量属性:
>>> avg.__code__.co_varnames ('value',) >>> avg.__code__.co_freevars ('total', 'count')
可以看到total和count已经被识别为自由变量了。
内容的提问来源于stack exchange,提问作者ViM
相关产品推荐
相关产品推荐

