为什么Python的非本地关键字不像全局范围?

时间:2013-06-01 14:15:55

标签: python python-3.x

在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关键字states的文档(重点已添加):

  

非本地语句会导致列出的标识符引用   先前绑定的变量位于最近的封闭范围中。

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

请仔细阅读本位

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

  

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

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

4 个答案:

答案 0 :(得分:6)

名称的搜索顺序是LEGB,即Local,Enclosing,Global,Builtin。因此,全球范围不是一个封闭的范围。

修改

来自docs

  

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

答案 1 :(得分:3)

答案是全球范围并没有包含任何内容 - 它对所有事物都是全球性的。在这种情况下使用global关键字。

答案 2 :(得分:1)

  

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

如果你在module的命名空间中添加了一些名字;它在任何使用module的模块中都可见,即它对整个Python进程都是全局的。

通常,您的应用程序应使用尽可能少的可变全局变量。见Why globals are bad?

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

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

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

您可以在PEP: 3104 Access to Names in Outer Scopes中了解nonlocal背后的历史和动机。

答案 3 :(得分:0)

这取决于边界案例:

nonlocals带有一些我们需要注意的敏感区域。首先,与全局语句不同,当评估非本地语时,非本地名称实际上必须先在封闭的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

其次,非本地将范围查找限制为仅包含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通常不知道创建一个全新名称的封闭范围,这些限制是有意义的。在之前的列表中,垃圾邮件应该在测试人员<中分配/ strong>,还是外面的模块?因为这是不明确的,Python必须在函数创建时解决非局部,而不是函数调用时间。