访问封闭scop中定义的变量

2024-05-26 11:54:40 发布

您现在位置:Python中文网/ 问答频道 /正文

从词汇范围界定的Google Style Guide开始:

A nested Python function can refer to variables defined in enclosing functions, but can not assign to them.

这两种情况在一开始似乎都得到了证实:

# 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

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

^{pr2}$

Tags: toreturnstyledefgooglefunctionoutcan
2条回答

在第一种情况下,您引用的是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

在第二种情况下,创建一个局部变量a,这也很好(局部a将与非本地变量不同,这就是为什么原始的{}没有被更改)。在

^{pr2}$

在第三种情况下,您创建了一个局部变量,但在此之前有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()

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

def toplevel():
    a = 5
    def nested():
        nonlocal a
        print(a + 2)
        a = 7
    nested()
    return a

对于任何遇到这个问题的人,除了这里公认的答案之外,它在Python docs中得到了简洁的回答:

This code:

>>> x = 10
>>> def bar():
...     print(x)
>>> bar()
10

works, but this code:

>>> x = 10
>>> def foo():
...     print(x)
...     x += 1

results in an UnboundLocalError.

This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope. Since the last statement in foo assigns a new value to x, the compiler recognizes it as a local variable. Consequently when the earlier print(x) attempts to print the uninitialized local variable and an error results.

In the example above you can access the outer scope variable by declaring it global:

>>> x = 10
>>> def foobar():
...     global x
...     print(x)
...     x += 1
>>> foobar()
10

You can do a similar thing in a nested scope using the nonlocal keyword:

>>> def foo():
...    x = 10
...    def bar():
...        nonlocal x
...        print(x)
...        x += 1
...    bar()
...    print(x)
>>> foo()
10
11

相关问题 更多 >