You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 22:03:39