python中奇怪的作用域行为

python中奇怪的作用域行为,python,python-3.x,scope,Python,Python 3.x,Scope,考虑以下python代码片段: x=1 Foo类: x=2 def foo(): x=3 Foo类: 打印(x)#打印3 Foo.Foo() 正如预期的那样,这将打印3。 但是,如果我们在上述代码段中添加一行,行为会发生变化: x=1 Foo类: x=2 def foo(): x=3 Foo类: x+=10 打印(x)#打印11 Foo.Foo() 而且,如果我们在上述示例中切换两行的顺序,结果将再次发生变化: x = 1 class Foo: x = 2 def foo()

考虑以下python代码片段:

x=1
Foo类:
x=2
def foo():
x=3
Foo类:
打印(x)#打印3
Foo.Foo()
正如预期的那样,这将打印3。 但是,如果我们在上述代码段中添加一行,行为会发生变化:

x=1
Foo类:
x=2
def foo():
x=3
Foo类:
x+=10
打印(x)#打印11
Foo.Foo()
而且,如果我们在上述示例中切换两行的顺序,结果将再次发生变化:

x = 1
class Foo:
    x = 2
    def foo():
        x = 3
        class Foo:
            print(x) # prints 1
            x += 10
Foo.foo()

我想了解为什么会发生这种情况,更一般地说,我想了解导致这种行为的范围规则。根据LEGB范围规则,我希望这两个代码段都打印3、13和3,因为在封闭函数
foo()
中定义了
x
,类块范围是特殊的。有文件证明:

类定义是一个可执行语句,它可以使用和定义 名字这些引用遵循名称解析的正常规则 例外情况是,未绑定的局部变量在 全局命名空间。类定义的命名空间成为 类的属性字典。中定义的名称的范围 类块仅限于类块;它不延伸到 方法的代码块–这包括理解和生成器 表达式,因为它们是使用函数作用域实现的

基本上,类块不会“参与”创建/使用封闭作用域

因此,这实际上是第一个没有像文档中描述的那样工作的示例。我认为这是一个真正的错误

编辑:

好的,实际上,这里有一些更相关的文档,我认为它们实际上与文档是一致的:

类主体作为exec(主体,globals())执行(大约), 名称空间)。与对exec()的正常调用的关键区别在于 词法作用域允许类主体(包括任何方法) 类时引用当前作用域和外部作用域中的名称 定义发生在函数内部

所以类块确实参与使用封闭作用域,但用于自由变量(这是正常的)。在我引用的第一篇文档中,关于“在全局名称空间中查找未绑定的局部变量”的部分适用于编译器通常标记为局部的变量。因此,考虑这个臭名昭著的错误,例如:

x = 1
def foo():
    x += 1
    print(x)

foo()
将引发未绑定的本地错误,但会引发等效的类定义:

x = 1
class Foo:
    x += 1
    print(x)
将打印
2

基本上,如果类块中的任何位置都有赋值语句,则它是“局部的”,但它将在全局范围内检查是否有未绑定的局部,而不是抛出
UnboundLocal
错误

因此,在您的第一个示例中,它不是局部变量,它只是一个自由变量,解析通过正常规则。在接下来的两个示例中,您使用了一个赋值语句mnt,将
x
标记为“local”,因此,如果它在本地名称空间中未绑定,将在全局名称空间中查找它