我遇到了一个有关变量范围的内部函数问题。我设法简单地将代码指向了确切的问题。因此,从以下开始:
def outer(foo):
def inner(bar):
print(foo)
print(bar)
return inner
if __name__ == "__main__":
function = outer("foo")
function("bar")
我将得到预期的输出:
foo
bar
但是,如果我尝试重新分配foo,则会收到错误消息:
def outer(foo):
def inner(bar):
foo = "edited " + foo
print(foo)
print(bar)
return inner
哪个给:
UnboundLocalError: local variable 'foo' referenced before assignment
这让我想起了全局变量,您可以在其中正常“读取”它们,但要“写入”,则必须执行“全局变量; variable = ...”。是一样的情况吗?如果是这样,是否存在一个关键字,可以从内部修改foo?又为什么呢?当然,一旦我创建了函数,就将foo固定为该函数。即不是全球性的。这里要避免什么问题?
答案 0 :(得分:3)
[...]是否有一个关键字可以允许从内部修改foo?
确实有这样一个关键字:nonlocal
def outer(foo):
def inner(bar):
nonlocal foo
foo = "edited " + foo
print(foo)
print(bar)
return inner
outer("foo")("bar")
输出:
edited foo
bar
来自docs:
nonlocal_stmt :: =“非本地”标识符(“,”标识符)*
nonlocal语句使列出的标识符引用最近的封闭范围(全局变量除外)中的先前绑定的变量。这很重要,因为绑定的默认行为是首先搜索本地名称空间。该语句允许封装的代码在全局(模块)范围之外的本地范围之外重新绑定变量。
在非本地语句中列出的名称与在全局语句中列出的名称不同,必须引用封闭范围内的现有绑定(不能明确确定应在其中创建新绑定的范围)。
非本地语句中列出的名称不得与本地范围内的现有绑定冲突。
关于why
部分:
代码块中的任何赋值(x = y)都会将变量的范围更改为当前范围。因此,要从全局范围引用和修改(*)变量,我们需要关键字global
,但是在这种情况下,我们需要来自“最近封闭”范围的变量,因此我们需要关键字nonlocal
(*)通过分配进行修改;可变全局变量仍然可以使用不带global / nonlocal关键字的相应方法进行修改。