[英]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?
那么为什么它不起作用呢?
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 编辑
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?
看看为什么全局变坏了? :
:
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()函数范围的限制(在编译时检查绑定) 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必须在函数创建时解析非局部,而不是函数调用时间。
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.
毕竟,“全局变量”的概念比词法闭包更容易解释。
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.