nonlocal在Python 3.x中做什么?
关闭调试问题,OP需要非局部的,并没有意识到它,请使用Is it possible To modify variable in python that Is outer, but not global, scope?代替。
虽然Python 2在2020年1月1日正式不支持,但如果出于某种原因,您被迫维护Python 2。并且需要与nonlocal等价的,请参见Python 2.x中的nonlocal关键字。
nonlocal在Python 3.x中做什么?
关闭调试问题,OP需要非局部的,并没有意识到它,请使用Is it possible To modify variable in python that Is outer, but not global, scope?代替。
虽然Python 2在2020年1月1日正式不支持,但如果出于某种原因,您被迫维护Python 2。并且需要与nonlocal等价的,请参见Python 2.x中的nonlocal关键字。
当前回答
引用自Python 3
非局部语句导致列出的标识符引用之前在最近的封闭范围内绑定的变量(不包括全局变量)。
如参考文献中所述,在多个嵌套函数的情况下,只有最近的封闭函数中的变量被修改:
def outer():
def inner():
def innermost():
nonlocal x
x = 3
x = 2
innermost()
if x == 3: print('Inner x has been modified')
x = 1
inner()
if x == 3: print('Outer x has been modified')
x = 0
outer()
if x == 3: print('Global x has been modified')
# Inner x has been modified
“最近的”变量可能在几层之外:
def outer():
def inner():
def innermost():
nonlocal x
x = 3
innermost()
x = 1
inner()
if x == 3: print('Outer x has been modified')
x = 0
outer()
if x == 3: print('Global x has been modified')
# Outer x has been modified
但它不能是一个全局变量:
def outer():
def inner():
def innermost():
nonlocal x
x = 3
innermost()
inner()
x = 0
outer()
if x == 3: print('Global x has been modified')
# SyntaxError: no binding for nonlocal 'x' found
其他回答
在谷歌中搜索“python nonlocal”,可以找到提案PEP 3104,它完整地描述了语句背后的语法和推理。简而言之,它的工作方式与global语句完全相同,只是它用于引用对函数来说既不是全局变量也不是局部变量的变量。
下面是一个简单的例子,说明您可以使用它做什么。可以重写计数器生成器来使用它,使它看起来更像带有闭包的语言的习惯用法。
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
显然,你可以把它写成一个生成器,像这样:
def counter_generator():
count = 0
while True:
count += 1
yield count
但是,虽然这是完美的python习惯用法,但对于初学者来说,第一个版本似乎更明显一些。通过调用返回的函数正确使用生成器是一个常见的混淆点。第一个版本显式返回一个函数。
help('nonlocal') The nonlocal statement nonlocal_stmt ::= "nonlocal" identifier ("," identifier)* 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. Names listed in a nonlocal statement, unlike to those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously). Names listed in a nonlocal statement must not collide with pre- existing bindings in the local scope. See also: PEP 3104 - Access to Names in Outer Scopes The specification for the nonlocal statement. Related help topics: global, NAMESPACES
来源:Python语言参考
a = 0 #1. global variable with respect to every function in program
def f():
a = 0 #2. nonlocal with respect to function g
def g():
nonlocal a
a=a+1
print("The value of 'a' using nonlocal is ", a)
def h():
global a #3. using global variable
a=a+5
print("The value of a using global is ", a)
def i():
a = 0 #4. variable separated from all others
print("The value of 'a' inside a function is ", a)
g()
h()
i()
print("The value of 'a' global before any function", a)
f()
print("The value of 'a' global after using function f ", a)
简而言之,它允许您在外部(但非全局)作用域中为变量赋值。参阅PEP 3104了解所有血腥的细节。
比较一下,不使用nonlocal:
x = 0
def outer():
x = 1
def inner():
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
# inner: 2
# outer: 1
# global: 0
为此,使用非局部,其中inner()的x现在也是outer()的x:
x = 0
def outer():
x = 1
def inner():
nonlocal x
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
# inner: 2
# outer: 2
# global: 0
如果我们要使用global,它会将x绑定到正确的“global”值:
x = 0
def outer():
x = 1
def inner():
global x
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
# inner: 2
# outer: 1
# global: 2