在全局命名空间中查找类定义中未绑定的局部变量-这是什么意思?

Cra*_*Man 1 python scoping

https://docs.python.org/3/reference/executionmodel.html#resolution-of-names的最后一段说

在名称解析的上下文中,exec()和eval()的类定义块和参数是特殊的。类定义是可以使用和定义名称的可执行语句。这些引用遵循通常的名称解析规则,但在全局命名空间中查找未绑定的局部变量。

引用文字的最后一句是什么意思?起初,我从中推断出将打印以下代码1

a = 1

def foo():
    a = 2
    def bar():
        class Bar:
            b = a
        print(Bar.b)
    bar()

foo()
Run Code Online (Sandbox Code Playgroud)

但我错了-由上面的代码组成的模块,在运行时,会打印出2,即a类定义中的名称,即使它未绑定在类定义块中且未绑定在其外部的本地块中,也是如此。与文档所说的相反,它在全局名称空间中查找。

我尝试了下面描述的另一个代码段(使用一条del语句,该语句是将变量绑定到其中的构造)

a = 1

def foo():
    a = 2
    def bar():
        class Bar:
            del a
        print(Bar.b)
    bar()

foo()
Run Code Online (Sandbox Code Playgroud)

但是del声明提出了NameError: name 'a' is not defined

所以,我不明白,那句话是什么意思?

Kev*_*vin 6

根据文档

如果名称绑定在块中,则该名称是该块的局部变量,除非声明为非局部或全局变量。

在您的第一个代码块中,a未绑定任何class Bar定义,因此它不是该块的局部变量。

绑定名称的一种方法是在赋值语句的左侧使用它。这是一个例子。

a = 1
def foo():
    a = 2
    class Bar:
        b = a
        a = 3
    print(Bar.b)
foo()
Run Code Online (Sandbox Code Playgroud)

结果:

1
Run Code Online (Sandbox Code Playgroud)

这说明了“在全局名称空间中查找未绑定的局部变量”的原理- b = a使用的值a而不是ato 的局部值foo


在您的第二个示例中,由于确定名称范围的目的是因为“在del语句中出现的目标也被视为绑定” ,因此a 认为是class Bar块的局部。但是“在全局名称空间中查找未绑定的局部变量”并不相关,因为del不需要查找名称的值即可解除绑定。

为了达到良好的效果,我们可以通过实验确认一条del语句向解释器传达一个名称应被视为本地名称的信号。

a = 1
def foo():
    a = 2
    class Bar:
        print(a)
        del a
foo()
Run Code Online (Sandbox Code Playgroud)

结果:

1
Traceback (most recent call last):
  File "C:\Users\Kevin\Desktop\test.py", line 7, in <module>
    foo()
  File "C:\Users\Kevin\Desktop\test.py", line 4, in foo
    class Bar:
  File "C:\Users\Kevin\Desktop\test.py", line 6, in Bar
    del a
NameError: name 'a' is not defined
Run Code Online (Sandbox Code Playgroud)

在这里,我们看到print(a)成功查找了局部变量的值a,然后在下一行它崩溃了,因为del无法删除未绑定的局部变量。

  • “ a = 3”确实绑定了“ a”,但仅在执行该语句时才绑定它。因此,当在我的第一个代码段中执行“ b = a”时,“ a = 3”尚未运行,因此“ a”尚未绑定。尽管如此,仍将“ a”视为“类Bar”作用域的局部变量,因为[“如果在代码块内的任何位置进行了名称绑定操作,则该块内对该名称的所有使用都将视为对当前块的引用。 ”(https://docs.python.org/3/reference/executionmodel.html#resolution-of-names) (2认同)