Python 中的范围是如何确定的

How scope is determined in Python

为什么第二个函数中的第一个 print 语句会抛出 x 未定义的错误?

x = 5

def function_a():
    print(x)


def function_b():
    print(x)
    x = 7
    print(x)

运行 第一个函数给出以下结果。

>>> function_a()
5

而 运行 第二个函数抛出错误。

UnboundLocalError: local variable 'x' referenced before assignment

在第二种方法中,你写了 x = 7,这使得 x 成为该方法的局部变量。但是,由于您试图在“x = 7”行之前的 print 语句中访问它,它会抛出一个错误,指出局部变量 x 在赋值之前被访问。

如果你删除行 x = 7,它会工作得很好。 你可以试试这个

x = 5

def vs_code():
    print(x)

def vs_code1():
    print(x)
    y = 7
    print(y)

这将打印 5个 5个 7

现在,因为我没有在第二种方法中声明 x,所以现在 x 不是第二种方法的局部变量。如果您在第二个方法中声明它,它会将其解释为局部变量。而且你只能在分配后使用它。

希望你明白了。

python 变量作用域特殊

您可以使用 dis 模块查看发生了什么。

def foo():
    print(x)
    print(y)
    x = ...
import dis
dis.dis(foo)

产出

  2           0 LOAD_GLOBAL              0 (print)
              2 LOAD_FAST                0 (x)
              4 CALL_FUNCTION            1
              6 POP_TOP

  3           8 LOAD_GLOBAL              0 (print)
             10 LOAD_GLOBAL              1 (y)
             12 CALL_FUNCTION            1
             14 POP_TOP

  4          16 LOAD_CONST               1 (Ellipsis)
             18 STORE_FAST               0 (x)
             20 LOAD_CONST               0 (None)
             22 RETURN_VALUE

x 是 LOAD_FAST

y 是 LOAD_GLOBAL 在运行之前,python认为x是一个局部变量,因为你试图修改它(不能修改全局变量)。

这会很好用

def vs_code1():
    global x
    print(x)
    x = 7
    print(x)

当变量在函数内部赋值时,该变量名被认为是局部的。除非使用以下行明确声明为全局:

global x

在函数的第一次打印中,变量 x 未在局部范围内定义。这就是为什么抛出错误。

所以你必须在函数体的开头添加行 global x 因为变量 x 被认为是全局的,尽管它是在函数中分配的。

Python 将 推断 并在看到范围内声明的变量时使用内部范围内的变量, 即使该变量是使用后声明.

为了演示这一点,我创建了两个场景。


在内部范围内声明的变量

变量按以下顺序推断:本地、非本地和全局。由于 x 是在内部范围内声明的,因此 Python 将推断并使用此范围内的 x,即使它是在使用后声明的。

注意Python不能区分修改声明;从全局范围修改 x 的意思被解释为在该范围内声明另一个变量 x

内部范围内没有声明变量

如果内部作用域内没有声明变量,Python 会将推断作用域切换到非本地,然后切换到全局。

显式切换作用域

如果事先明确声明了x的范围,Python就不用推断了。

以下代码不会抛出错误,因为它使用的范围明确是全局范围而不是内部范围。

x = 5

def scope():
    global x
    print(x)
    x = 7
    print(x)

范围

通过选择要使用的范围,您不仅可以使用 该特定范围内的变量,而且可以修改 变量。因此,在处理范围时需要格外小心。

因为Python无法区分变量声明变量修改,我的建议是,如果你想使用全局变量,你应该事先明确说明。

这也适用于嵌套范围。

x = 5

def outer():
    x = 7

    def inner():
        nonlocal x
        print(x)
        x = 3
        print(x)
    
    inner()

运行 外部函数给出以下结果。

>>> outer()
7
3

尝试将 nonlocal 关键字更改为 global 并查看不同的结果;或完全删除该行以获得错误。