在Python中,是否有可能修改一个位于外部(封闭)而非全局作用域中的变量?
在Python中,是否有可能修改一个位于外部(封闭)而非全局作用域中的变量?
考虑下面的例子:
def A(): b = 1 def B(): # 我可以在这里访问'b'。 print(b) # 但我可以在这里修改'b'吗? B() A()
对于B
函数中的代码,变量b
处于一个非全局的封闭(外部)作用域。我如何在B
中修改b
?如果我直接尝试,会出现UnboundLocalError
错误,并且使用global
也无法解决问题,因为b
不是全局的。
Python 实现的是词法作用域,而不是动态作用域 - 就像几乎所有现代语言一样。这里的技巧不会允许访问调用者的变量 - 除非调用者也恰好是封闭函数 - 因为调用者不在作用域内。有关这个问题的更多信息,请参见How can I access variables from the caller, even if it isn't an enclosing scope (i.e., implement dynamic scoping)?。
在Python中,如果想要修改一个处于外部(包围)但不是全局范围的变量,可以使用nonlocal关键字。这是因为默认情况下,变量的绑定会先在局部命名空间中进行搜索。而nonlocal语句允许封装的代码重新绑定局部作用域之外的变量,除了全局(模块)作用域。
在Python 3中,可以使用nonlocal关键字来实现这一点。如下例所示:
def foo(): a = 1 def bar(): nonlocal a a = 2 bar() print(a) # 输出: 2
在Python 2中,可以使用可变对象(如列表或字典)并对值进行修改,而不是重新分配变量。如下例所示:
def foo(): a = [] def bar(): a.append(1) bar() bar() print a foo()
输出:
[1, 1]
另一种方法是在外部作用域中使用`class nonlocal: pass`,然后在内部作用域中可以对`nonlocal.x`进行赋值。
这种行为的逻辑是:在Python中,`a = 2`语句是有歧义的,因为它既用于声明新变量,也用于修改现有变量(例如,与Scheme进行比较,Scheme有单独的`let`和`set!`)。Python 2无法区分所需的含义,因此默认假定需要一个新变量。Python 3默认采用相同的行为,但允许使用`nonlocal`关键字来使用另一种行为。
更多关于这个的问题和示例代码可以参考这个链接:stackoverflow.com/questions/1261875
在Python中,有时候我们希望在内部函数中修改外部(封闭)作用域中的变量,但不是全局作用域中的变量。然而,Python的作用域规则并不允许直接修改外部作用域中的变量。为了解决这个问题,我们可以使用一个空的类来临时存储变量,从而创建一个临时作用域。这个方法使得代码更加优雅。
首先,我们定义一个外部函数outer_fn(),其中包含一个内部函数inner_fn()。为了创建一个临时作用域,我们在outer_fn()中定义了一个空的类FnScope,里面包含了变量b和c。
接下来,在inner_fn()中,我们可以通过使用FnScope来访问和修改临时作用域中的变量。在这个例子中,我们通过FnScope.b += 1来修改变量b的值,并通过FnScope.c += FnScope.b来修改变量c的值。在outer_fn()中,我们连续三次调用了inner_fn(),以便看到变量的修改效果。
当我们运行outer_fn()时,会得到如下的输出结果:8 27。这表明变量b被成功地修改为8,并且变量c也被相应地修改为27。
然而,如果我们尝试在外部作用域中访问FnScope,会得到一个NameError的错误提示,因为FnScope只在inner_fn()中可见,而不在外部作用域中可见。
为了解决这个问题,我们可以使用"nonlocal"关键字来定义外部变量。这样,我们就可以在inner_fn()中访问和修改外部作用域中的变量。另外,我们还可以通过在外部作用域中初始化一个字典,并在内部函数中设置字典的键来实现类似的效果。
总结起来,要在Python中修改外部作用域中的变量,我们可以使用一个临时的类来创建一个临时作用域,并通过"nonlocal"关键字或者设置字典的键来访问和修改外部作用域中的变量。这样,我们就可以在内部函数中修改外部作用域中的变量,从而解决了这个问题。
问题的出现原因是在Python中,内部函数无法直接修改外部(包围)作用域中的变量。这是因为在Python中,变量的作用域是基于函数的,每个函数都有自己的作用域。
解决方法是将外部变量包装在一个列表中。通过将外部变量赋值给列表的元素,内部函数可以修改列表的元素值,从而实现修改外部变量的效果。
以下是一个示例代码:
def A(): b = [1] def B(): b[0] = 2 B() print(b[0]) # 输出结果为 '2'
不过,从Python 3开始,引入了nonlocal
关键字,可以直接修改外部变量。在Python 3.9及更高版本中,可以使用nonlocal
关键字来实现修改外部变量的效果。