Python的非本地化取决于层次结构的级别?

时间:2011-11-08 12:40:17

标签: scope python-3.x closures

这个问题是对a question about Python variable scope的跟进。其他问题q1q2answers可以在SO上找到,甚至更多。 官方Python documentationPEP 3104应该解释详细信息,但对我来说似乎并不完全不言自明。

我想要解决的主题是通过在一个层次结构上/下移动代码来重构包含nonlocal / global的代码。

我不理解的是Python引用中这句话的含义:

  

非本地语句中列出的名称,与a中列出的名称不同   全局语句,必须引用封闭的预先存在的绑定   范围(应该创建新绑定的范围不能   毫不含糊地确定。)

在全局范围内给出以下代码:

var = 0
def outer():
    global var                  # line A
    var = 1
    def inner():
        nonlocal var            # line B
        var = 2

        print('inner:', var)

    inner()
    print('outer:', var)

outer()
print('main:', var)

执行会引发错误:

SyntaxError: no binding for nonlocal 'var' found

代码可以工作(当然,如果任何一行A被注释掉,则会有不同的语义:

inner: 2
outer: 2
main: 0

或B行被注释掉:

inner: 2
outer: 1
main: 1

但是,在上面的例子中,由于nonlocal应该将var绑定到“封闭范围”,我希望A行将外部/ var绑定到全局范围,然后B行查找outer / var并将inner / var重新绑定到global / var。相反它似乎根本找不到它(由于A线中的重新绑定,我想)并引发错误。

我期望的结果是:

inner: 2
outer: 2
main: 2

这只是Python中范围界定令人困惑的另一个例子吗?

或者,为了使这成为一个建设性的问题:

  • 如何以一种函数所在的级别无关紧要的方式编写这样的示例(必须与global交换nonlocal,反之亦然)?
  • 如果函数位于中间层和未知级别的层次结构中,outer()的作者如何更改既不是最外层(在本例中为全局)级别,也不是inner()级别的代码不得不感动? -

在我对语言的谦虚理解中,这些结构(对闭包的依赖)只是要避免。其他人已经建议使用其他语言功能(classesfunc attrs)来实现这种上下文敏感度。

2 个答案:

答案 0 :(得分:10)

globalnonlocal无意合并。它们意味着不同的东西:

  • global表示名称存在于模块级别
  • nonlocal表示名称存在于外部词法函数范围

您获得原始异常的原因是因为您告诉Python var是非本地的(意味着它在外部函数定义中),但是没有函数级绑定对于任何外部函数定义中的var因为你在外部函数中告诉Python var是全局的。

答案 1 :(得分:0)

  

如何以一种无关紧要的方式编写这样的例子   功能所在的级别(必须与全局交换)   非本地的,反之亦然)?

函数所在的级别无关紧要。它只关乎变量所在的级别。

  

如果函数位于中间和未知级别   层次结构,outer()的作者怎么能改变代码呢   既不是最外层(在这种情况下是全局),也不是内部()   水平必须被触及?

您正在询问中间级别的函数是否可能通过更改其代码中的某些内容,使内部函数中的变量交替更改全局范围内的某些内容或外部函数的本地范围内的某些内容。这似乎是一件非常奇怪的事情。