【问题标题】:Why isn't Python switching from enclosing to local variable scope?为什么 Python 不从封闭变量范围切换到局部变量范围?
【发布时间】:2020-11-21 14:46:49
【问题描述】:

我只是在检查我关于 Python 范围界定的心智模型并感到困惑。前两个示例匹配我的模型,第三个示例不匹配。

我假设 Python 有 4 个作用域:

  • 本地
  • 封闭
  • 全球
  • 内置

我想这 4 个作用域就像字典一样。内置的一个是预定义的,其他的是在一些操作后生成的:

  • 全局:主脚本文件创建一个变量。脚本完成执行后,此作用域将被终止。
  • 本地:在函数内调用变量。一旦函数执行完毕,这个作用域就会被杀死
  • 封闭:函数B 在函数A 中定义。一旦调用了BA 的本地范围就变成了B 的封闭范围。一旦 B 完成执行,此作用域就会被终止。

我假设 Python 在内存中有这 4 个字典,并且基本上每次都尝试所有 4 个:

  1. 变量是否存在于本地范围内?用它。如果没有,请转到 2
  2. 变量是否存在于封闭范围内?用它。如果没有,请转到 3。
  3. 变量是否存在于全局范围内?用它。如果没有,请转到 4。
  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

【问题讨论】:

  • 我还注意到def x(): y 给出了NameError,但def x(): y; y = 1 给出了UnboundLocalError。错误后的含义代码会影响错误。我不确定这是我的心智模型的另一个问题还是同样的问题。
  • 在运行时唯一可能发生的后备是全局 -> 内置。将变量分类为局部变量、非局部变量(您所谓的“封闭”)或全局变量完全是在编译时进行的;基本上,如果该函数中没有明确的 globalnonlocal 声明,您分配给(函数中的任何位置)的任何变量都会变为局部变量。
  • @jasonharper 如果您将该评论作为答案,我会接受。如果您添加有关 Python 如何执行内容的更多详细信息(编译时会发生什么,运行时会发生什么),我会 +1(或 +50)是 :-)

标签: python scope


【解决方案1】:

规则是,如果您在函数体内的任何位置分配给变量,则该变量被视为局部变量 - 在整个函数中。

如果你想引用一个全局变量,你必须通过声明明确地说出来

global my_variable

如果你的意思是在定义它的最近的封闭范围内引用变量,你必须将它声明为

nonlocal my_variable

所以,这里没有什么特别的事情发生:决定变量是局部变量的一般规则仍然适用。

【讨论】:

    猜你喜欢
    • 2016-11-13
    • 1970-01-01
    • 2016-08-19
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    • 2014-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多