如何在Python中正确修改闭包的内部状态?
闭包修改内部状态的问题解析
为什么两个示例的行为不同?
第一个示例里,sample是列表(可变对象),inner_mean中调用sample.append(number)是对这个列表的原地修改——没有给sample重新赋值(比如没写sample = 新列表)。Python会直接引用外层作用域的sample变量,不会将其视为内部函数的局部变量,因此能正常保留状态并运行。
第二个示例里,y是浮点数(不可变对象),_lpf中写了y = (1 - fc/fs)*y + ...——这里的y = ...属于重新赋值操作。Python默认会把这种情况下的y判定为_lpf的局部变量,但右边计算时又用到了y,此时局部的y还未定义,就会抛出variable 'y' in enclosing scope is referenced before assignment错误。
如何修改第二个示例?
有两种常用方法实现保留y的状态:
方法1:用nonlocal关键字声明
在内部函数开头添加nonlocal y,告诉Python该y不是局部变量,而是来自外层嵌套作用域的变量,这样赋值操作会直接修改外层的y:
def lpf(fs): y = 0.0 def _lpf(fc, u): nonlocal y # 声明y来自外层作用域 y = (1 - fc / fs) * y + fc / fs * u return y return _lpf
方法2:用可变对象包裹y
和第一个示例逻辑一致,把y放到列表(可变对象)中,通过修改列表元素来更新状态,避免重新赋值:
def lpf(fs): y = [0.0] # 用列表包裹y,变成可变对象 def _lpf(fc, u): y[0] = (1 - fc / fs) * y[0] + fc / fs * u return y[0] return _lpf
修改后运行你的测试代码,第二次调用lpf_zero_three(1.2, 3.1)会自动使用前一次调用后的y值计算,符合需求。
内容的提问来源于stack exchange,提问作者Barzi2001
相关产品推荐
相关产品推荐

