为什么 Python 不从封闭变量范围切换到局部变量范围?
Why isn't Python switching from enclosing to local variable scope?
我只是在检查 Python 中关于范围界定的心智模型,然后感到困惑。前两个示例与我的模型匹配,第三个示例不匹配。
我假设 Python 有 4 个作用域:
- 本地
- 封闭
- 全球
- 内置
我想这 4 个范围就像字典一样。内置的是预定义的,其他的是在一些操作后生成的:
- 全局:主脚本文件创建一个变量。一旦脚本执行完毕,这个作用域就会被终止。
- 局部:在一个函数中,一个变量被调用。一旦函数完成执行,这个范围就会被终止
- 封闭:函数
B
定义在函数 A
中。一旦 B
被调用,A
的局部作用域就变成了 B
的封闭作用域。一旦 B
完成执行,此范围将被终止。
我假设 Python 内存中有这 4 个词典,基本上每次都尝试全部 4 个:
- 变量是否存在于本地范围内?用它。如果不是,则转到 2
- 变量是否存在于封闭范围内?用它。否,转3。
- 变量是否存在于全局范围内?用它。否,转4。
- 变量是否存在于内置函数中?用它。如果不是,则抛出
NameError
我特别假设变量可以从正在使用的封闭范围切换到正在使用的局部范围。显然不是这样。有人可以解释为什么吗?我的心理模型与实际发生的情况是否可能存在更大差异?
示例 1
这会打印“本地”
def foo():
min = lambda n: "enclosing"
def bar():
"""Bar is enclosed by 'foo'"""
min = lambda n: "local"
print(min([1, 2, 3]))
bar()
foo()
示例 2
这会打印“封闭”
def foo():
min = lambda n: "enclosing"
def bar():
"""Bar is enclosed by 'foo'"""
print(min([1,2,3]))
bar()
foo()
示例 3
def foo():
min = lambda n: "enclosing"
def bar():
"""Bar is enclosed by 'foo'"""
print(min([1,2,3]))
min = lambda n: "local"
print(min([1, 2, 3]))
bar()
foo()
给予
Traceback (most recent call last):
File "example.py", line 13, in <module>
foo()
File "example.py", line 10, in foo
bar()
File "example.py", line 6, in bar
print(min([1,2,3]))
UnboundLocalError: local variable 'min' referenced before assignment
规则是,如果您在函数体内的任何位置赋值给变量,则该变量在整个函数中都被视为局部变量。
如果你想引用一个全局变量,你必须通过声明明确说明
global my_variable
如果你想在定义它的最近封闭范围内引用变量,你必须将它声明为
nonlocal my_variable
因此,这里没有发生任何特殊情况:确定变量是局部变量的一般规则仍然适用。
我只是在检查 Python 中关于范围界定的心智模型,然后感到困惑。前两个示例与我的模型匹配,第三个示例不匹配。
我假设 Python 有 4 个作用域:
- 本地
- 封闭
- 全球
- 内置
我想这 4 个范围就像字典一样。内置的是预定义的,其他的是在一些操作后生成的:
- 全局:主脚本文件创建一个变量。一旦脚本执行完毕,这个作用域就会被终止。
- 局部:在一个函数中,一个变量被调用。一旦函数完成执行,这个范围就会被终止
- 封闭:函数
B
定义在函数A
中。一旦B
被调用,A
的局部作用域就变成了B
的封闭作用域。一旦B
完成执行,此范围将被终止。
我假设 Python 内存中有这 4 个词典,基本上每次都尝试全部 4 个:
- 变量是否存在于本地范围内?用它。如果不是,则转到 2
- 变量是否存在于封闭范围内?用它。否,转3。
- 变量是否存在于全局范围内?用它。否,转4。
- 变量是否存在于内置函数中?用它。如果不是,则抛出
NameError
我特别假设变量可以从正在使用的封闭范围切换到正在使用的局部范围。显然不是这样。有人可以解释为什么吗?我的心理模型与实际发生的情况是否可能存在更大差异?
示例 1
这会打印“本地”
def foo():
min = lambda n: "enclosing"
def bar():
"""Bar is enclosed by 'foo'"""
min = lambda n: "local"
print(min([1, 2, 3]))
bar()
foo()
示例 2
这会打印“封闭”
def foo():
min = lambda n: "enclosing"
def bar():
"""Bar is enclosed by 'foo'"""
print(min([1,2,3]))
bar()
foo()
示例 3
def foo():
min = lambda n: "enclosing"
def bar():
"""Bar is enclosed by 'foo'"""
print(min([1,2,3]))
min = lambda n: "local"
print(min([1, 2, 3]))
bar()
foo()
给予
Traceback (most recent call last):
File "example.py", line 13, in <module>
foo()
File "example.py", line 10, in foo
bar()
File "example.py", line 6, in bar
print(min([1,2,3]))
UnboundLocalError: local variable 'min' referenced before assignment
规则是,如果您在函数体内的任何位置赋值给变量,则该变量在整个函数中都被视为局部变量。
如果你想引用一个全局变量,你必须通过声明明确说明
global my_variable
如果你想在定义它的最近封闭范围内引用变量,你必须将它声明为
nonlocal my_variable
因此,这里没有发生任何特殊情况:确定变量是局部变量的一般规则仍然适用。