Python内部函数变量范围

时间:2019-07-12 12:53:01

标签: python closures

我遇到了一个有关变量范围的内部函数问题。我设法简单地将代码指向了确切的问题。因此,从以下开始:

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固定为该函数。即不是全球性的。这里要避免什么问题?

1 个答案:

答案 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关键字的相应方法进行修改。