请考虑下面的Python代码片段:

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

正如预期的那样,这张照片打印了3张.

x = 1
class Foo:
    x = 2
    def foo():
        x = 3
        class Foo:
            x += 10
            print(x) # prints 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.

推荐答案

类块范围是特殊的.有here条记录:

类定义是可以使用和定义

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

所以,它实际上是the first example that isn't working as documented.我认为这是一个真正的错误

编辑:

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

类主体作为exec(body,globals()执行,

所以类块do参与using个封闭作用域,但用于自由变量(无论如何都是正常的).在我引用的第一篇文档中,关于"在全局名称空间中查找未绑定的局部变量"的部分适用于可能会导致异常的变量.因此,考虑这个臭名昭著的错误,例如:

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

foo()

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

x = 1
class Foo:
    x += 1
    print(x)

将打印2张.

基本上,如果类块中的任何地方都有赋值语句,则它是"局部的",但它将在全局范围内判断是否有未绑定的局部语句,而不是抛出UnboundLocal错误.

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

Python-3.x相关问答推荐

当索引大于一个整数而小于前一个索引时,我如何返回列值?

Pandas -我们如何在一行中应用多个要求

如何将python点击参数设置为与选项回调不同的参数的别名?

PANDAS中当前数据帧的匹配与更新

为什么空列表也能起作用?

链接列未延伸到数据框的末尾

在Pandas中,根据另一列中的重复值将数据分组为一列

通过 Pandas 通过用户定义函数重命名数据框列

pip install saxonche v 12.1.0 产生 FileNotFoundError

python 分代垃圾收集:get_count 没有报告正确的对象创建数?

转换Pandas 数据框 - 添加行

缺失时推断的数据类可选字段

如何使用 Selenium by class_name 从大学橄榄球数据中抓取图像 url 列表

在初始化之前禁用`__setattr__`的干净方法

如何禁用 pylint 禁止自用警告?

multiprocessing.Queue 中的 ctx 参数

Python 解包运算符 (*)

用 numpy nan 查找列表的最大值

在python中,如果一个函数没有return语句,它会返回什么?

python判断一个方法是否被调用而不模拟它