Python 3 添加了 nonlocal 关键字,把 None、True 和 False 提升为关键字,废弃了 print 和 exec。今天细说下 nonlocal 的用法
nonloacal是最近出现的保留关键字,在python3.0中引入。如果想自己实现函数装饰器,那就必须了解闭包的方方面面,因此也就需要知道nonloacal。
题外话:闭包除了在装饰器中有用处之外,还是回调式异步编程和函数时编程风格的基础。
这里借用《流畅的python》一书中的例子来说明下:
def make_averager(): count = 0 total = 0 def averager(new_value): count += 1 total += new_value return total / count return averager
调用执行,会得到如下结果:
>>> avg = make_averager() >>> avg(10) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 6, in averager UnboundLocalError: local variable 'count' referenced before assignment
问题是,当count是数字或任何不可变类型时,count += 1 语句的作用其实与count = count + 1一样。因此,我们在 averager 的定义体中为 count 赋值了,这会把 count 变成局部变量。total 变量也受这个问题影响。
对于不可变类型来说,只能读取,不能更新,如果尝试重新绑定,例如count = count + 1,其实会隐式创建局部变量 count。这样,count 就不是自由变量了,因此不会保存在闭包中。
为了解决这个问题,Python 3 引入了 nonlocal 声明。它的作用是把变量标记为自由变量,即使在函数中为变量赋予新值了,也会变成自由变量。如果为 nonlocal 声明的变量赋予新值,闭包中保存的绑定会更新,更新后的版本如下:
def make_averager(): count = 0 total = 0 def averager(new_value): nonlocal count, total count += 1 total += new_value return total / count return averager
在python2中没有nonlocal的情况下问题是怎么解决的呢?http://www.python.org/dev/peps/pep-3104/中的第三个代码片段给出了一种方法。基本上,这种处理方式是把内部函数需要修改的变量(如 count 和 total)存储为可变对象(如字典或简单的实例)的元素或属性,并且把那个对象绑定给一个自由变量。