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
并查看不同的结果;或完全删除该行以获得错误。
为什么第二个函数中的第一个 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
并查看不同的结果;或完全删除该行以获得错误。