装饰器中已声明变量却出现nonlocal绑定错误的原因咨询
为什么使用
nonlocal会触发绑定错误? 先看你给出的代码:
def decorator(func): def returning(): var = 1 func() print(var) return(returning) @decorator def function(): nonlocal var var = 5 function()
这个错误的核心是作用域的嵌套关系搞反了,咱们一步步理清楚:
nonlocal的作用是什么?
它是用来引用当前函数直接外层嵌套作用域里的变量,注意是「当前函数自己的外层」,不是随便哪个地方的变量。你的代码里的作用域关系是怎样的?
returning()是decorator内部的嵌套函数,它的var是自己作用域里的局部变量。- 被装饰的
function()是一个独立的顶级函数,它的外层作用域是全局作用域,和returning()的作用域没有任何嵌套关系!
当你调用function()时,其实是调用了returning(),在returning里执行func()也就是原来的function。这时候function里的nonlocal var会去寻找自己外层作用域(全局)里的var,但全局中根本没定义这个变量,自然就报错了——它完全不知道returning里有个var存在。
怎么解决这个问题?
如果想让function能修改returning里的var,得让两者的作用域产生关联,或者通过传递的方式让function能访问到这个变量,这里给两个简单的方案:
方案1:用可变对象传递(比如列表)
因为可变对象可以在函数内部修改其内容,不需要依赖作用域绑定:
def decorator(func): def returning(): var = [1] # 用列表包装变量 func(var) print(var[0]) return returning @decorator def function(var): var[0] = 5 # 修改列表里的元素 function() # 输出:5
方案2:让函数返回修改后的值
把var作为参数传给function,再接收返回的新值:
def decorator(func): def returning(): var = 1 var = func(var) # 接收function返回的新值 print(var) return returning @decorator def function(var): return 5 # 返回修改后的值 function() # 输出:5
内容的提问来源于stack exchange,提问作者GT 77
相关产品推荐
相关产品推荐

