def some_func(a):
def access_a():
print(a)
access_a()
输出a
的值。但是,如果我想在嵌套函数中更改a
:
def some_func(a):
def change_a():
a += 1
print(a)
change_a()
它提高了UnboundLocalError
异常。
我知道a
是一个非局部变量,但是为什么我可以在不声明nonlocal a
的情况下访问它?
python范围规则101:
-
除非明确声明为
global
(Python 2.x和3.x)或nonlocal
(仅Python 3.x),否则将绑定在功能体中的名称被视为local
。无论何时发生分配在功能的身体中,这都是正确的。试图在局部变量绑定之前读取当然是错误的。 -
如果读取名称但没有绑定在函数的身体中,则将在封闭示波器(如果有的话)中查找它。NB:函数参数实际上是本地名称,因此永远不会在封闭范围中查找它们。
请注意,a += 1
主要是a = a + 1
的快捷方式,因此在您的示例中,a
是局部的(绑定在函数的身体中,而不是明确声明的全局或非局限性),但是您尝试读取它(a = a+1
的RHS的RHS)。
在Python 3中,您可以使用nonlocal
语句解决此问题:
>>> def outer(a):
... def change():
... nonlocal a
... a += 1
... print("before : {}".format(a))
... change()
... print ("after : {}".format(a))
...
>>> outer(42)
before : 42
after : 43
python 2没有nonlocal
,因此规范的hack是将变量包裹在可变的容器中(通常是list
,但任何可变的对象都可以使用):
>>> def outer(a):
... _a = [a]
... def change():
... _a[0] += 1
... print("before : {}".format(_a[0]))
... change()
... print ("after : {}".format(_a[0]))
...
>>> outer(42)
before : 42
after : 43
至少可以说这很丑陋。
现在封闭非常方便,它们主要是对象的功能对应物:在保留此状态的封装时在一组函数之间共享状态的一种方法,因此,如果您发现自己需要nonlocal
变量适当的类可能是一个更干净的解决方案(尽管可能不是为了您的示例,而不是返回内部功能,而只能在内部使用它)。
我有两个解决方案:
#first one:
# try with list, compound data types dict/list
def some_func(a):
def change_a():
a[0] += 1
print(a[0])
change_a()
some_func([1])
>>> 2
#second one
#reference pointer
from ctypes import *
def some_func_ctypes(a):
def change_a():
a[0] += 1
print a.contents, a[0]
change_a()
i = c_int(1)
pi = pointer(i)
some_func_ctypes(pi)
>>> c_int(2) 2
使用+=
操作员时,将对a
的新值分配。这将a变成了口译员眼中的当地人。