可以修改Python中外部(封闭)作用域的变量吗,而不是全局作用域?
考虑这个例子:
def A():
b = 1
def B():
# I can access 'b' from here.
print(b)
# But can i modify 'b' here?
B()
A()
在B
函数里的代码中,变量b
是在一个非全局的、外部的范围内。那我该怎么在B
里修改b
呢?如果我直接尝试,就会出现UnboundLocalError
的错误,而使用global
也没用,因为b
并不是全局的。
Python使用的是词法作用域,而不是动态作用域——这和几乎所有现代编程语言一样。这里的方法不会让你访问到调用者的变量——除非调用者恰好也是一个外部函数——因为调用者不在作用域内。想了解更多这个问题,可以查看如何访问调用者的变量,即使它不是一个外部作用域(也就是实现动态作用域)?。
9 个回答
14
我对Python还不是很熟悉,但我稍微了解了一些。我认为你能找到的最好解决办法,跟Java的一个变通方法差不多,就是把你的外部变量放在一个列表里。
def A():
b = [1]
def B():
b[0] = 2
B()
print(b[0])
# The output is '2'
补充:我想在Python 3之前,这种说法可能是对的。现在看来,nonlocal
就是你需要的解决方案。
27
你可以用一个空的类来创建一个临时的作用域。这就像可变的东西,但看起来更好看一些。
def outer_fn():
class FnScope:
b = 5
c = 6
def inner_fn():
FnScope.b += 1
FnScope.c += FnScope.b
inner_fn()
inner_fn()
inner_fn()
这样会产生以下的互动输出:
>>> outer_fn()
8 27
>>> fs = FnScope()
NameError: name 'FnScope' is not defined
233
在Python 3中,可以使用nonlocal
关键字:
nonlocal
语句让你可以使用在最近的外层作用域中已经定义的变量,但不包括全局变量。这一点很重要,因为默认情况下,Python会先在本地作用域中查找变量。这个语句允许你在局部作用域之外重新绑定变量,但不包括全局(模块)作用域。
def foo():
a = 1
def bar():
nonlocal a
a = 2
bar()
print(a) # Output: 2
在Python 2中,可以使用一个可变对象(比如列表或字典),直接修改这个对象的值,而不是重新赋值给一个变量:
def foo():
a = []
def bar():
a.append(1)
bar()
bar()
print a
foo()
输出结果:
[1, 1]