为什么要使用nonlocal
Python3中加入了新的关键字nonlocal,当在一个嵌套的函数中对变量申明为nonlocal时,就明确表示这个变量是外部函数中定义的变量。也许会有这么一个问题:按照python的LEGB原则,在函数本地作用域找不到变量的情况下,解释器会自动在外层函数寻找,nonlocal关键字岂不是显得多余? 是的,当一个函数在本地作用域找不到变量申明时会向外层函数寻找,这在函数闭包中很常见。如下:
1 def test(num1): 2 def add(num2): 3 return num1 + num2 4 return add 5 6 a = test(1) 7 b = test(2) 8 print(a(1)) 9 print(b(1))
输出为:
2 3
但是在本地作用域中使用的变量后,还想对此变量进行更改赋值就会报错。如下:
def test(): count = 1 def add(): print(count) count += 1 return add a = test() a()
输出为:
--------------------------------------------------------------------------- UnboundLocalError Traceback (most recent call last) <ipython-input-6-24732f13d2b6> in <module>() 7 8 a = test() ----> 9 a() <ipython-input-6-24732f13d2b6> in add() 2 count = 1 3 def add(): ----> 4 print(count) 5 count += 1 6 return add UnboundLocalError: local variable 'count' referenced before assignment
在上面代码中,如果在使用count前面加上关键字nonlocal申明就可解决这个问题:
def add(): count = 1 def fun(): nonlocal count print(count) count += 1 return fun a = add() a() a()
输出为:
1 2
上面代码完美地解决了函数嵌套调用外部变量的问题;另外,如果从另一个角度来看我们给此函数增加了记录函数状态的功能。当然,这也可以通过申明全局变量来实现增加函数状态的功能。当这样会出现以下问题:
1. 每次调用函数时,都得在全局作用域申明变量。别人调用函数时还得查看函数内部代码。
2. 当函数在多个地方被调用并且同时记录着很多状态时,会造成非常地混乱。
使用nonlocal的好处是,在为函数添加状态时不用额外地添加全局变量,因此可以大量地调用此函数并同时记录着多个函数状态,每个函数都是独立、独特的。针对此项功能其实还个一个方法,就是使用类,通过定义__call__可实现在一个实例上直接像函数一样调用。