【问题标题】:Why is an uninitialized class variable looked up in the global scope and not the enclosing scope?为什么在全局范围而不是封闭范围中查找未初始化的类变量?
【发布时间】:2021-02-09 20:17:17
【问题描述】:

这不是我在编码项目中需要的问题,但我的一个朋友把它发给了我。 问题是:这里打印出什么?为什么?

x = 0
y = 0
def f():
    x = 1
    y = 1
    class A:
        print(x,y)
        x = 2
f()

输出:

0 1

我的第一直觉告诉我应该是“1 1”,但我错了。我摆弄了代码,发现如果我删除“x = 2”我会是正确的。但为什么呢?

此外,当我将变量设为全局变量时,它也起作用了。像这样:

x = 0
y = 0
def f():
    global x
    global y
    x = 1
    y = 1
    class A:
        print(x,y)
        x = 2
f()

输出:

1 1

我不是在寻找解决问题的其他方法,只是为了更好地了解这里发生的事情。

提前致谢

【问题讨论】:

  • 这是来自 a tweet 的 Guido van Rossum,他是从 kevmod's blog 获得的。
  • 太糟糕了,博客文章中指向原始 python-dev 线程的链接已失效(尽管它可能引用了PEP-227 上的线程)。

标签: python function class variables


【解决方案1】:

这在Resolution of names的最后一段中有记录:

exec() 和 eval() 的类定义块和参数是特殊的 在名称解析的上下文中。类定义是可执行文件 可以使用和定义名称的语句。这些参考遵循 名称解析的正常规则有一个例外是未绑定本地 在全局命名空间中查找变量。 (强调我的)

因此,正如预期的那样,在定义它的最近的封闭范围内查找yf 函数,它的值是 1)。

另一方面,x = 2 导致 x 被认为是本地的,并且由于它尚未在 print(x,y) 中定义,因此异常会导致在全局命名空间中查找它(它的值是 0 ),而不是像普通函数中未绑定的局部变量所期望的那样导致 NameError


我一直想知道为什么存在这个特殊规则,感谢@orlp 在问题下的评论,我才找到了答案。

问题中的代码似乎来自this 2014 blog post from KMOD'S BLOG,最近是tweeted by Guido van Rossum

正如有人问及原因,Guido answered

向后兼容 Python 2.1。

所以现在我们知道了...

【讨论】:

  • 呃,比我快,+1。
  • @orlp 谢谢,特别是 Guido 的推文链接,它解释了这条规则的原因!
猜你喜欢
  • 1970-01-01
  • 2016-11-13
  • 2016-06-29
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多