为什么这样做:
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
答案 0 :(得分:14)
该错误似乎不能很好地描述根本问题。迈克解释了这些消息,但这并没有解释根本原因。
实际问题是在python中你不能分配给已关闭的变量。所以在function2中'a'是只读的。当你分配给它时,你创建一个新的变量,正如迈克指出的那样,你在写之前就读过了。
如果你想从内部范围分配到外部变量,你必须像这样作弊:
def function1():
al = [10]
def function2():
print al[0]
al[0] -= 1
if al[0]>0:
function2()
function2()
所以al是不可变的,但它的内容不是,你可以在不创建新变量的情况下更改它们。
答案 1 :(得分:5)
应该注意,这是Python中的语法故障。 Python本身(在字节码级别)可以很好地分配给这些变量;在2.x中根本没有语法表示你想要这样做。它假定如果您在嵌套级别中分配变量,则表示它是本地的变量。
这是一个巨大的缺点;能够分配到闭包是至关重要的。我和charlieb的hack多次合作过。
Python 3使用非常难以命名的“非本地”关键字修复此问题:
def function1():
a = 10
def function2():
nonlocal a
print(a)
a -= 1
if a>0:
function2()
function2()
function1()
这种语法仅在3.x中可用,这是非常差的;大多数人都陷入2.x,并且必须继续使用黑客来解决这个问题。这非常需要向后移植到2.x。
答案 2 :(得分:3)
在非工作代码段中,当您说“a
”时,您可以指定a -= 1
。因此,在function2
内,a
是该范围的本地,而不是封闭范围。 Python的闭包是词法 - 它不会在a
的框架中动态查找function2
,如果尚未分配,则在function1
的框架中查找它。
请注意,这并不依赖于递归或完全使用闭包。考虑这个函数的例子
def foo():
print a
a = 4
调用它也会得到UnboundLocalError
。 (如果没有a = 4
,则会使用全局a
,或者如果没有NameError
,则会引发a
。因为def function1():
a = 10
def function2(a=a):
print a
a -= 1
if a > 0:
function2(a)
function2()
可能在该范围内分配,所以是当地的。
如果我正在设计此功能,我可能会使用更像
的方法for a in xrange(10, -1, -1): print a
(当然还是{{1}} ;-))