递归闭包中的范围错误
为什么这有效:
def function1():
a = 10
def function2():
print a
function2()
但这不起作用:
def function1():
a = 10
def function2():
print a
a -= 1
if a>0:
function2()
function2()
我收到此错误:
UnboundLocalError: local variable 'a' referenced before assignment
why does this work:
def function1():
a = 10
def function2():
print a
function2()
but this does not:
def function1():
a = 10
def function2():
print a
a -= 1
if a>0:
function2()
function2()
I get this error:
UnboundLocalError: local variable 'a' referenced before assignment
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
该错误似乎并不能很好地描述根本问题。迈克解释了这些消息,但没有解释根本原因。
实际的问题是在 python 中你不能分配给封闭变量。所以在 function2 中 'a' 是只读的。当您分配给它时,您创建了一个新变量,正如迈克指出的那样,您在写入之前先读取该变量。
如果你想从内部作用域分配给外部变量,你必须像这样作弊:
所以 al 是不可变的,但它的内容不是,你可以在不创建新变量的情况下更改它们。
The error doesn't seem to be very descriptive of the root problem. Mike explains the messages but that does not explain the root cause.
The actual problem is that in python you cannot assign to closed over variables. So in function2 'a' is read only. When you assign to it you create a new variable which, as Mike points out, you read before you write.
If you want to assign to the to the outer variable from the inner scope you have to cheat like so:
So al is immutable but its contents are not and you can change them without creating a new variable.
需要注意的是,这是 Python 中的一个语法错误。 Python 本身(在字节码级别)可以很好地分配给这些变量; 2.x 中根本没有语法来表明您想要这样做。它假设如果您分配给嵌套级别中的变量,则意味着它是该变量的本地变量。
这是一个很大的缺点;能够分配给闭包是基础。我已经用 charlieb's hack 多次解决了这个问题。
Python 3 使用名称非常尴尬的“nonlocal”关键字修复了这个问题:
很糟糕的是,这种语法仅在 3.x 中可用;大多数人都停留在 2.x 中,并且不得不继续使用 hack 来解决这个问题。这迫切需要向后移植到 2.x。
http://www.python.org/dev/peps/pep-3104/
It should be noted that this is a syntax glitch in Python. Python itself (at the bytecode level) can assign to these variables just fine; there's simply no syntax in 2.x to indicate that you want to do so. It assumes that if you assign to a variable in a nesting level, you mean for it to be a local to it.
This is a huge shortcoming; being able to assign to closures is fundamental. I've worked around this with charlieb's hack several times.
Python 3 fixes this with the very awkwardly-named "nonlocal" keyword:
It's very poor that this syntax is only available in 3.x; most people are stuck in 2.x, and have to continue using hacks to work around this problem. This badly needs to be backported to 2.x.
http://www.python.org/dev/peps/pep-3104/
在非工作代码段中,当您说“
a -= 1
”时,您将分配给a
。因此,在 function2 内部,a 是该作用域的本地变量,而不是封闭的作用域。 Python 的闭包是词法的 - 它不会在function2
的框架中动态查找a
,如果尚未分配,则在function1
中查找它代码> 的框架。请注意,这根本不依赖于递归性或使用闭包。考虑一下这个函数的例子
,调用它也会给你带来一个
UnboundLocalError
。 (如果没有a = 4
,它将使用全局a
,或者如果没有,则引发NameError
。)因为a
可能在该范围内分配,它是本地的。如果我正在设计这个函数,我可能会使用类似的方法
(或者当然
for a in xrange(10, -1, -1): print a
;-) )In the non-working snippet, you assign to
a
when you say "a -= 1
". Because of that, insidefunction2
,a
is local to that scope, not taken the enclosing scope. Python's closures are lexical—it does not dynamically look fora
infunction2
's frame and if it has not been assigned go and look for it infunction1
's frame.Note that this doesn't depend on the recursiveness or using closures at all. Consider the example of this function
Calling it will get you an
UnboundLocalError
too. (Withouta = 4
it would either use the globala
or, if there isn't one, raise aNameError
.) Becausea
is potentially assigned within that scope, it is local.If I was designing this function, I might use an approach more like
(or of course
for a in xrange(10, -1, -1): print a
;-) )