访问在封闭范围中定义的变量

Bra*_*mon 5 python python-3.x

来自Google样式指南的词法范围:

嵌套的Python函数可以引用封闭函数中定义的变量,但不能赋值给它们.

这两个似乎最初都要检查:

# Reference
def toplevel():
    a = 5
    def nested():
        print(a + 2)
    nested()
    return a
toplevel()
7
Out[]: 5

# Assignment
def toplevel():
    a = 5
    def nested():
        a = 7 # a is still 5, can't modify enclosing scope variable
    nested()
    return a
toplevel()
Out[]: 5
Run Code Online (Sandbox Code Playgroud)

那么,为什么嵌套函数中的引用和赋值的组合会导致异常呢?

# Reference and assignment
def toplevel():
    a = 5
    def nested():
        print(a + 2)
        a = 7
    nested()
    return a
toplevel()
# UnboundLocalError: local variable 'a' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

Moh*_*ohd 11

在第一种情况下,您指的是一个nonlocal好的变量,因为没有调用局部变量a.

def toplevel():
    a = 5
    def nested():
        print(a + 2) # theres no local variable a so it prints the nonlocal one
    nested()
    return a
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,您创建一个本地变量a也很好(本地a将与非本地变量不同,这就是为什么原始a未被更改).

def toplevel():
    a = 5 
    def nested():
        a = 7 # create a local variable called a which is different than the nonlocal one
        print(a) # prints 7
    nested()
    print(a) # prints 5
    return a
Run Code Online (Sandbox Code Playgroud)

在第三种情况下,您创建一个局部变量,但print(a+2)在此之前就已经存在,这就是引发异常的原因.因为print(a+2)将引用a在该行之后创建的局部变量.

def toplevel():
    a = 5
    def nested():
        print(a + 2) # tries to print local variable a but its created after this line so exception is raised
        a = 7
    nested()
    return a
toplevel()
Run Code Online (Sandbox Code Playgroud)

要实现您想要的,您需要nonlocal a在内部函数内部使用:

def toplevel():
    a = 5
    def nested():
        nonlocal a
        print(a + 2)
        a = 7
    nested()
    return a
Run Code Online (Sandbox Code Playgroud)

  • 尽管它是一种解释性语言,但在运行之前会检查整个语法。看看[这个](/sf/answers/482285891/)和[这个](https://softwareengineering.stackexchange.com/questions/263982/why-is-python-treatment-as -当它有编译阶段时的解释语言) (2认同)

Bra*_*mon 11

对于任何遇到此问题的人,除了此处接受的答案外,Python 文档中还对其进行了简明回答:

这段代码:

>>> x = 10
>>> def bar():
...     print(x)
>>> bar()
10
Run Code Online (Sandbox Code Playgroud)

有效,但这段代码:

>>> x = 10
>>> def foo():
...     print(x)
...     x += 1
Run Code Online (Sandbox Code Playgroud)

结果是UnboundLocalError.

这是因为当您对作用域中的变量进行赋值时,该变量将成为该作用域的局部变量,并隐藏外部作用域中任何类似命名的变量。由于 foo 中的最后一条语句为 分配了一个新值x,编译器将其识别为局部变量。因此,当之前print(x)尝试打印未初始化的局部变量时会导致错误。

在上面的示例中,您可以通过声明来访问外部作用域变量global

>>> x = 10
>>> def foobar():
...     global x
...     print(x)
...     x += 1
>>> foobar()
10
Run Code Online (Sandbox Code Playgroud)

您可以使用nonlocal 关键字在嵌套范围内执行类似的操作:

>>> def foo():
...    x = 10
...    def bar():
...        nonlocal x
...        print(x)
...        x += 1
...    bar()
...    print(x)
>>> foo()
10
11
Run Code Online (Sandbox Code Playgroud)