21

在 Python 3.3.1 中,这有效:

i = 76

def A():
    global i
    i += 10

print(i) # 76
A()
print(i) # 86

这也有效:

def enclosing_function():
    i = 76
    def A():
        nonlocal i
        i += 10

    print(i) # 76
    A()
    print(i) # 86

enclosing_function()

但这不起作用:

i = 76
def A():
    nonlocal i # "SyntaxError: no binding for nonlocal 'i' found"
    i += 10

print(i)
A()
print(i)

nonlocal关键字状态的文档(添加了重点):

nonlocal 语句使列出的标识符引用最近的封闭范围中先前绑定的变量。

在第三个示例中,“最近的封闭范围”恰好是全局范围。那么为什么它不起作用呢?

请阅读本文

我确实注意到文档继续说明(强调添加):

[ nonlocal] 语句允许封装代码重新绑定全局(模块)范围之外的局部范围之外的变量。

但是,严格来说,这并不意味着我在第三个示例中所做的事情不应该起作用。

4

4 回答 4

10

名称的搜索顺序是 LEGB,即 Local、Enclosure、Global、Builtin。所以全局范围不是封闭范围。

编辑

文档

nonlocal 语句导致列出的标识符引用最近的封闭范围内的先前绑定的变量。这很重要,因为绑定的默认行为是首先搜索本地命名空间。该语句允许封装代码重新绑定全局(模块)范围之外的局部范围之外的变量。

于 2013-06-01T14:20:57.070 回答
4

为什么模块的范围被认为是全局的而不是封闭的?它对其他模块仍然不是全局的(好吧,除非你这样做from module import *),是吗?

如果您将某些名称放入module's 命名空间;它在任何使用moduleie 的模块中都是可见的,它对于整个 Python 进程都是全局的。

通常,您的应用程序应尽可能少地使用可变全局变量。请参阅为什么全局变量不好?

  • 非地方性
  • 没有访问控制或约束检查
  • 隐式耦合
  • 并发问题
  • 命名空间污染
  • 测试和限制

因此,如果nonlocal允许意外创建全局变量会很糟糕。如果要修改全局变量;您可以直接使用global关键字。

  • global是最具破坏性的:可能会影响程序中任何地方的模块的所有使用
  • nonlocal破坏性较小:受 external() 函数范围的限制(在编译时检查绑定)
  • 没有声明(局部变量)是破坏性最小的选项:受 inner() 函数范围的限制

您可以阅读 PEP 背后nonlocal的历史和动机:3104 Access to Names in Outer Scopes

于 2013-06-02T14:02:24.930 回答
3

这取决于边界情况:

外地人有一些我们需要注意的敏感区域。首先,与 global 语句不同,当评估 nonlocal 时,nonlocal名称确实必须先前已分配在封闭的 def 范围内,否则您将收到错误 - 您无法通过在封闭范围内重新分配它们来动态创建它们。实际上,在调用任何一个或嵌套函数之前,它们会在函数定义时进行检查

>>>def tester(start):
      def nested(label):
         nonlocal state   #nonlocals must already exist in enclosing def!
         state = 0
         print(label, state)
      return nested
SyntaxError: no binding for nonlocal 'state' found

>>>def tester(start):
      def nested(label):
          global state   #Globals dont have to exits yet when declared
          state = 0      #This creates the name in the module now
          print(label, state)
      return nested

>>> F = tester(0)
>>> F('abc')
abc 0
>>> state
0

其次,nonlocal将范围查找限制为仅包含 defs;nonlocals 不会在封闭模块的全局范围或所有 def 之外的内置范围中查找,即使它们已经存在:

例如:-

>>>spam = 99
>>>def tester():
      def nested():
         nonlocal spam  #Must be in a def, not the module!
         print('current=', spam)
         spam += 1
      return nested
SyntaxError: no binding for nonlocal 'spam' found

一旦您意识到 python 通常不知道在其中创建全新名称的封闭范围,这些限制就有意义了。在前面的清单中,应该在tester中分配spam还是在外部模块中分配垃圾邮件?因为这是模棱两可的,Python 必须在函数创建时解析非本地变量,而不是函数调用时。

于 2015-06-22T17:13:06.220 回答
2

答案是全局范围不包含任何东西——它对所有东西都是全局的。global在这种情况下使用关键字。

于 2013-06-01T14:18:22.100 回答