可以修改Python中外部(封闭)作用域的变量吗,而不是全局作用域?

210 投票
9 回答
110144 浏览
提问于 2025-04-17 08:03

考虑这个例子:

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]

撰写回答