python nonloacal

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)存储为可变对象(如字典或简单的实例)的元素或属性,并且把那个对象绑定给一个自由变量。

 

posted @ 2018-04-23 10:58  40块钱抓娃娃  阅读(337)  评论(0编辑  收藏  举报