【问题标题】:Python nonlocal statement in a class definition类定义中的 Python 非本地语句
【发布时间】:2011-07-24 21:17:02
【问题描述】:

我正在尝试对 Python 3 源代码中的范围进行一些分析,但我对 nonlocal 语句在类定义中的工作方式感到困惑。

据我了解,类定义在新命名空间内执行其主体(称为 dict),并将类名绑定到 type(name, bases, dict) 的结果。只要非本地 x 引用绑定在封闭非本地范围内某处的变量,它就应该工作。

据此,我希望以下代码能够编译并运行:

class A:
    v = 1
    class B:
        nonlocal v
        v = 2

但这失败了

SyntaxError: no binding for nonlocal 'v' found

而下面的代码运行完美

def A():
    v = 1
    class B:
        nonlocal v
        v = 2

谁能解释一下函数定义的闭包和类定义的区别?

【问题讨论】:

  • 更多研究 - 在最后一个代码示例中,A 中的 locals() 是 {v:1},而 B 中是 {v:2, '__module__':'__main__' , '__locals__':{...}}

标签: python class python-3.x python-nonlocal


【解决方案1】:

词法作用域仅适用于函数命名空间,否则在类中定义的方法将能够“看到”类级别的属性(这是设计使然 - 这些属性必须改为作为方法内的 self 的属性来访问) .

导致类级别变量被方法引用跳过的相同限制也使nonlocal 关键字无法发挥其魔力。 (global 确实有效,因为它不依赖于词法作用域机制)

【讨论】:

  • 谢谢,这是有道理的。我曾假设有一些非常基本的堆栈形式在每个级别都可以正常工作。注意到 symtable 模块文档改变了我的想法,但直到你的回答我才真正明白发生了什么或为什么。
【解决方案2】:

Python 处理类和函数定义的方式截然不同。例如,您的 A.v 不是 A 的变量,而是它的属性。因此,类创建的命名空间不是作用域。 nonlocal 在您尝试使用它时不起作用,我并不感到惊讶。

【讨论】:

  • 感谢您的回复。因此,函数作用域是在运行时创建的,而不是在定义时创建的。我假设类定义的主体是立即在不同的命名空间中执行的,这不是仅在执行期间创建一个范围吗? - 我想知道这是否与内部类无法访问外部类的属性的原因相同......
  • 它确实创建了一个临时范围,但它是一个不同的种类范围。编译器使用不同的规则来决定哪些属性是可见的(用于从内部范围引用和写入外部范围)。
猜你喜欢
  • 2010-11-18
  • 2018-04-24
  • 2014-03-22
  • 2014-04-01
  • 2010-12-14
  • 2016-08-01
相关资源
最近更新 更多