首页 > 解决方案 > Python内部函数变量范围

问题描述

我在编写的关于变量范围的内部函数时遇到了问题。我已经设法简化代码以指出确切的问题。所以开始:

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  

这让我想起了全局变量,您可以在其中正常“读取”它们,但要“写入”您必须执行“全局变量;变量 =...”。是不是一样的情况?如果是这样,是否有允许从内部修改 foo 的关键字?还有为什么?当然,一旦我创建了函数,那么 foo 就为该函数固定了。即不是全球性的。这里要避免什么问题?

标签: pythonclosures

解决方案


[...] 是否有允许从内部修改 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

文档

nonlocal_stmt ::= "nonlocal" 标识符 ("," 标识符)*

nonlocal 语句导致列出的标识符引用最近的封闭范围内的先前绑定的变量,不包括全局变量。这很重要,因为绑定的默认行为是首先搜索本地命名空间。该语句允许封装代码重新绑定全局(模块)范围之外的局部范围之外的变量。

与 global 语句中列出的名称不同,在 nonlocal 语句中列出的名称必须引用封闭范围中的预先存在的绑定(无法明确确定应创建新绑定的范围)。

非本地语句中列出的名称不得与本地范围内的预先存在的绑定发生冲突。

至于why部分:

代码块中的任何赋值 (x = y) 都会将变量的范围更改为当前范围。因此,要从全局范围引用和修改 (*) 变量,我们需要关键字global,但在这种情况下,我们需要来自“最近封闭”范围的变量,因此我们需要关键字nonlocal

(*) 通过赋值修改;可变全局变量仍然可以使用它们各自的方法修改,而无需 global/nonlocal 关键字。


推荐阅读