简体   繁体   English

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

[英]Why doesn't Python's nonlocal keyword like the global scope?

In Python 3.3.1, this works:在 Python 3.3.1 中,这有效:

i = 76

def A():
    global i
    i += 10

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

This also works:这也有效:

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

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

enclosing_function()

But this doesn't work:但这不起作用:

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

print(i)
A()
print(i)

The documentation for the nonlocal keyword states (emphasis added): nonlocal关键字状态的文档(已添加重点):

The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope . nonlocal 语句导致列出的标识符引用最近的封闭 scope中先前绑定的变量。

In the third example, the "nearest enclosing scope" just happens to be the global scope.在第三个示例中,“最近的封闭范围”恰好是全局 scope。 So why doesn't it work?那么为什么它不起作用呢?

PLEASE READ THIS BIT请阅读本文

I do notice that the documentation goes on to state (emphasis added):我确实注意到文档继续到 state(已添加重点):

The [ nonlocal ] statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope . [ nonlocal ] 语句允许封装代码重新绑定本地 scope除了全局(模块) scope 之外的变量

but, strictly speaking, this doesn't mean that what I'm doing in the third example shouldn't work.但是,严格来说,这并不意味着我在第三个示例中所做的事情不应该起作用。

The search order for names is LEGB, ie Local, Enclosing, Global, Builtin. 名称的搜索顺序是LEGB,即Local,Enclosing,Global,Builtin。 So the global scope is not an enclosing scope. 因此全局范围不是封闭范围。

EDIT 编辑

From the docs : 来自文档

The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope. 非本地语句使列出的标识符引用最近的封闭范围中的先前绑定的变量。 This is important because the default behavior for binding is to search the local namespace first. 这很重要,因为绑定的默认行为是首先搜索本地名称空间。 The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope. 除了全局(模块)范围之外,该语句还允许封装代码重新绑定局部范围之外的变量。

The answer is that the global scope does not enclose anything - it is global to everything. 答案是全球范围并没有包含任何内容 - 它对所有事物都是全球性的。 Use the global keyword in such a case. 在这种情况下使用global关键字。

why is a module's scope considered global and not an enclosing one? 为什么模块的范围被认为是全局的而不是封闭的? It's still not global to other modules (well, unless you do from module import * ), is it? 它仍然不是其他模块的全局(好吧,除非你from module import * ),是吗?

If you put some name into module 's namespace; 如果你在module的命名空间中加入一些名称; it is visible in any module that uses module ie, it is global for the whole Python process. 它在任何使用module模块中都可见,即它对于整个Python进程是全局的。

In general, your application should use as few mutable globals as possible. 通常,您的应用程序应使用尽可能少的可变全局变量。 See Why globals are bad? 看看为什么全局变坏了? :

  • Non-locality 非局域
  • No Access Control or Constraint Checking 无访问控制或约束检查
  • Implicit coupling 隐含耦合
  • Concurrency issues 并发问题
  • Namespace pollution 命名空间污染
  • Testing and Confinement 测试和限制

Therefore It would be bad if nonlocal allowed to create globals by accident. 因此,如果nonlocal允许意外创建全局变量,那将是很糟糕的。 If you want to modify a global variable; 如果要修改全局变量; you could use global keyword directly. 你可以直接使用global关键字。

  • global is the most destructive: may affect all uses of the module anywhere in the program global是最具破坏性的:可能会影响程序中任何位置的模块的所有使用
  • nonlocal is less destructive: limited by the outer() function scope (the binding is checked at compile time) nonlocal的破坏性较小:受outer()函数范围的限制(在编译时检查绑定)
  • no declaration (local variable) is the least destructive option: limited by inner() function scope no声明(局部变量)是破坏性最小的选项:受inner()函数范围的限制

You can read about history and motivation behind nonlocal in PEP: 3104 Access to Names in Outer Scopes . 您可以在PEP中阅读nonlocal背后的历史和动机:3104访问外部范围内的名称

It depends upon the Boundary cases: 这取决于边界情况:

nonlocals come with some senstivity areas which we need to be aware of. nonlocals带有一些我们需要注意的敏感区域。 First, unlike the global statement, nonlocal names really must have previous been assigned in an enclosing def's scope when a nonlocal is evaluated or else you'll get an error-you cannot create them dynamically by assigning them anew in the enclosing scope. 首先,与全局语句不同,当评估非本地语时, 非本地名称实际上必须先在封闭的def范围内分配,否则您将收到错误 - 您无法通过在封闭范围内重新分配它们来动态创建它们。 In fact, they are checked at function definition time before either or nested function is called 实际上,在调用任一函数或嵌套函数之前,会在函数定义时检查它们

>>>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

Second, nonlocal restricts the scope lookup to just enclosing defs; 其次, nonlocal将范围查找限制为仅包含defs; nonlocals are not looked up in the enclosing module's global scope or the built-in scope outside all def's, even if they are already there: 在封闭模块的全局范围内或在所有def之外的内置范围中都不会查找nonlocals,即使它们已经存在:

for example:- 例如:-

>>>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

These restrictions make sense once you realize that python would not otherwise generally know enclosing scope to create a brand-new name in. In the prior listing, should spam be assigned in tester , or the module outside? 一旦你意识到python通常不会知道创建一个全新名称的封闭范围,这些限制是有意义的。在之前的列表中, 垃圾邮件是应该在测试人员中分配还是在外面的模块中分配? Because this is ambiguous, Python must resolve nonlocals at function creation time, not function call time. 因为这是不明确的,Python必须在函数创建时解析非局部,而不是函数调用时间。

Historical reasons历史原因

In 2.x, nonlocal didn't exist yet.在 2.x 中, nonlocal还不存在。 It wasn't considered necessary to be able to modify enclosing, non-global scopes;没有必要修改封闭的非全局范围; the global scope was seen as a special case.全局 scope 被视为一个特例。 After all, the concept of a "global variable" is a lot easier to explain than lexical closures.毕竟,“全局变量”的概念比词法闭包更容易解释。

The global scope works differently全球scope工作方式不同

Because functions are objects, and in particular because a nested function could be return ed from its enclosing function (producing an object that persists after the call to the enclosing function), Python needs to implement lookup into enclosing scopes differently from lookup into either local or global scopes. Because functions are objects, and in particular because a nested function could be return ed from its enclosing function (producing an object that persists after the call to the enclosing function), Python needs to implement lookup into enclosing scopes differently from lookup into either local or全局范围。 Specifically, in the reference implementation of 3.x, Python will attach a __closure__ attribute to the inner function, which is a tuple of cell instances that work like references (in the C++ sense) to the closed-over variables.具体来说,在 3.x 的参考实现中,Python 会将__closure__属性附加到内部 function,这是一个cell实例的元组,其工作方式类似于引用(在 ZF6F87C9FDCF8B3C3F0Z7F93 的封闭变量意义上)。 (These are also references in the reference-counting garbage-collection sense; they keep the call frame data alive so that it can be accessed after the enclosing function return s.) (这些也是引用计数垃圾收集意义上的引用;它们使调用帧数据保持活动状态,以便在封闭的 function return s 之后可以访问它。)

By contrast, global lookup works by doing a chained dictionary lookup: there's a dictionary that implements the global scope, and if that fails, a separate dictionary for the builtin scope is checked.相比之下,全局查找通过链式字典查找来工作:有一个字典实现了全局 scope,如果失败,则检查内置 scope 的单独字典。 (Of course, writing a global only writes to the global dict, not the builtin dict; there is no builtin keyword.) (当然,一个全局只写全局字典,而不是内置字典;没有builtin关键字。)

Theoretically, of course, there's no reason why the implementation of nonlocal couldn't fall back on a lookup in the global (and then builtin) scope, in the same way that a lookup in the global scope falls back to builtins.当然,从理论上讲,nonlocal 的实现没有理由不能依赖全局(然后是内置的) nonlocal中的查找,就像在全局 scope 中的查找回退到内置一样。 Stack Overflow is not the right place to speculate on the reason behind the design decision. Stack Overflow 不适合推测设计决策背后的原因。 I can't find anything relevant in the PEP , so it may simply not have been considered.在 PEP 中找不到任何相关内容,因此可能根本没有考虑过。

The best I can offer is: like with local variable lookup, nonlocal lookup works by determining at compile time what the scope of the variable will be.我能提供的最好的方法是:与局部变量查找一样, nonlocal查找通过在编译时确定变量的 scope 将是什么来工作。 If you consider builtins as simply pre-defined, shadow-able globals (ie the only real difference between the actual implementation and just dumping them into the global scope ahead of time, is that you can recover access to the builtin with del ), then so does global lookup.如果您将内置函数视为简单的预定义、可阴影全局变量(即,实际实现与提前将它们转储到全局 scope 之间的唯一真正区别是您可以使用del恢复对内置函数的访问),那么global查找也是如此。 As they say, "simple is better than complex" and "special cases aren't special enough to break the rules";正如他们所说,“简单胜于复杂”和“特殊情况不足以打破规则”; so, no fallback behaviour.所以,没有后备行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM