请考虑下面的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相关问答推荐

丢弃重复的索引,并在多索引数据帧中保留一个

在BaseHTTPRequestHandler中填充和返回列表

在Python代码中包含NAN值时,以两个矩阵计算RMSE

使用Python抓取sofascore以获取有关球队阵容和投票的信息

对大型数据框中的选定列进行重新排序

在 python pandas 中设置条件和分配新值

列出相同索引的Pandas

将元组列表转换为以整个元组为键的字典列表

XPATH:使用 .find_elements_by_xpath 为未知数量的 xpath 输入值

正则表达式:匹配字符串中的分隔符(字母和特殊字符)以形成新的子字符串

pysftp vs. Paramiko

asyncio.Semaphore RuntimeError: Task got Future 附加到不同的循环

如何使用 d.items() 更改 for 循环中的所有字典键?

AttributeError:系列对象没有属性iterrows

python setup.py egg_info mysqlclient

用于 unicode 大写单词的 Python 正则表达式

为什么 Python 不能识别我的 utf-8 编码源文件?

Python 3中星型导入的函数形式是什么

有效地判断一个元素是否在列表中至少出现 n 次

如何从 seaborn / matplotlib 图中删除或隐藏 x 轴标签