在下面的例子中taster
返回函数nested
,以备之后调用。对变量state
的搜索符合通常的变量搜索规则。
>>> def tester(start):
... state = start
... def nested(label):
... print(label, state)
... return nested
...
>>> F = tester(0)
>>> F('spam')
spam 0
>>> F('ham')
ham 0
默认情况下被嵌套的函数不能够对闭包函数内变量改变:
>>> def tester(start):
... state = start
... def nested(label):
... print(label, state)
... state += 1
... return nested
...
>>> F = tester(0)
>>> F('spam')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in nested
UnboundLocalError: local variable 'state' referenced before assignment
使用nonlocal改变变量
>>> def tester(start):
... state = start
... def nested(label):
... nonlocal state
... print(label, state)
... state += 1
... return nested
...
>>> F = tester(0)
>>> F('spam')
spam 0
>>> F('ham') #state可以累加
ham 1
>>> F('eggs')
eggs 2
就像通常的闭包函数的引用,我们调用tester
多少次就会在内存中有对少个state
的拷贝。闭包作用域中的state
对象是和函数返回的nested
函数对象相捆绑的。每次调用就会产生一个完全不同的state
对象,例如更新一个函数的state
并不会影响另一个,下面的例子可以解释:
>>> G = tester(42)
>>> G('spam')
spam 42
>>> G('eggs')
eggs 43
>>> F('bacon')
bacon 3
边界情况
尽管nonlocal十分有用,但有一些情况必须事先知道。首先,不像global,nonlocal声明的变量必须事先赋值,否则会抛出错误:
>>> def tester(start):
... def nested(label):
... nonlocal state
... state = 0
... print(label, state)
... return nested
...
File "<stdin>", line 3
SyntaxError: no binding for nonlocal 'state' found
>>> def tester(start):
... def nested(label):
... global state
... state = 0
... print(label, state)
... return nested
...
>>> F = tester(0)
>>> F('abc')
abc 0
>>> state
0
其次,nonlocal限制作用域只在闭包函数中寻找。nonlocal不会往上在模块的全局作用域或者函数之外的Python内置作用域:
>>> spam = 99
>>> def tester():
... def nested():
... nonlocal spam
... print('Current=', spam)
... spam += 1
... return nested
...
File "<stdin>", line 3
SyntaxError: no binding for nonlocal 'spam' found