我有这样的代码(简化):
def outer():
ctr = 0
def inner():
ctr += 1
inner()
但ctr
会导致错误:
Traceback (most recent call last):
File "foo.py", line 9, in <module>
outer()
File "foo.py", line 7, in outer
inner()
File "foo.py", line 5, in inner
ctr += 1
UnboundLocalError: local variable 'ctr' referenced before assignment
我该如何解决这个问题?我认为嵌套的范围可以让我这样做。我试过'全球',但它仍然无效。
答案 0 :(得分:32)
如果您使用的是Python 3,则可以使用nonlocal
语句启用非本地名称的重新绑定:
def outer():
ctr = 0
def inner():
nonlocal ctr
ctr += 1
inner()
如果您使用的是没有nonlocal
的Python 2,则需要在没有裸名称重新绑定的情况下执行递增(通过将计数器保留为某个裸名称的项目或属性,不< / strong>作为一个裸名称本身)。例如:
...
ctr = [0]
def inner():
ctr[0] += 1
...
,当然,无论您在其他地方使用裸ctr[0]
,都可以使用ctr
。
答案 1 :(得分:6)
来自http://www.devshed.com/c/a/Python/Nested-Functions-in-Python/1/
嵌套函数体中的代码可能 访问(但不重新绑定)本地 外部函数的变量也是 称为嵌套的自由变量 功能
因此,您需要明确地将ctr
传递给inner
。
答案 2 :(得分:6)
每当将值分配给函数内部的变量时,python都会将该变量视为该函数的局部变量。由于语句ctr += 1
包含对ctr
的赋值,因此python认为ctr
是inner
函数的局部变量。因此,它甚至从不尝试查看在ctr
中定义的outer
变量的值。 python看到的本质上是这样的:
def inner():
ctr = ctr + 1
我想我们都可以同意该代码会导致错误,因为ctr
在定义之前就已被访问。
(有关Python如何确定变量范围的更多信息,另请参见this question。)
Python 3引入了nonlocal
statement,其工作原理与global
语句非常相似,但是允许我们访问周围函数的变量(而不是全局变量)。只需在nonlocal ctr
函数顶部添加inner
,问题就会消失:
def outer():
ctr = 0
def inner():
nonlocal ctr
ctr += 1
inner()
由于nonlocal
语句在python 2中不存在,因此我们必须谨慎。有两种简单的解决方法:
删除所有对ctr
的分配
由于python仅将ctr
视为局部变量,因为存在对该变量的赋值,因此如果我们删除所有名称为ctr
的赋值,问题将消失。但是,如何在不赋值的情况下更改变量的值呢?简单:我们将变量包装在一个可变对象中,例如列表。然后,我们可以修改该列表,而无需为名称ctr
分配值:
def outer():
ctr = [0]
def inner():
ctr[0] += 1
inner()
将ctr
作为参数传递给inner
def outer():
ctr = 0
def inner(ctr):
ctr += 1
return ctr
ctr = inner(ctr)
答案 3 :(得分:-1)
如何在ctr
之外(即在全局范围内)或任何其他类/函数声明outer
?这将使变量可访问和写入。