美文网首页
简谈Python3关键字nonlocal使用场景

简谈Python3关键字nonlocal使用场景

作者: ByiProX | 来源:发表于2019-12-10 15:23 被阅读0次

下面是之前提过的有待提升效率的计算移动平均的方法:

def make_averager():
    series = []
    def averager(new_value):
        series.append(new_value)
        total = sum(series)
        return total/len(series)
    return averager

我们在文章简谈Python闭包中设计的计算移动平均的方法效率并不高,原因是我们存储了所有的历史数据在列表中,然后在每次调用averager时使用sum求和。要实现同样的功能,更好的实现方法是只存储当前的总值和元素个数,使用这两个值计算移动平均值即可。

直观来思考,我们可以对代码进行如下改进(注意:代码有缺陷!)

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 5, in averager
UnboundLocalError: local variable 'count' referenced before assignment

提示错误为变量count在赋值前进行了引用,实际上,total也存在相同的问题,只是count变量处提前抛出了UnboundLocalError异常。接下来进一步解释,首先我们需要明白一个前提,在Python中,对于一个不可变数据类型比如上述示例中的count,count+=1和count=count+1是等效的。对于可变数据类型的讨论,可以参考文章浅析Python中列表操作之*和*=

因此,我们在averager的定义体中为count赋值了,这会把count变成局部变量,total变量也受这个问题影响。

先前版本没遇到这个问题,因为我们没有给series赋值,我们只是调用series.append,并把它传给sum和len。也就是说,我们利用了列表是可变的对象这一事实。

但是对数字、字符串、元组等不可变类型来说,只能读取,不能更新。如果尝试重新绑定,例如count=count+1,其实会隐式创建局部变量count。这样,count就不是自由变量了,因此不会保存在闭包中。

为了解决这个问题,Python3引入了nonlocal声明。它的作用是把变量标记为自由变量,即使在函数中为变量赋予新值了,也会变成自由变量。如果为nonlocal声明的变量赋予新值,闭包中保存的绑定会更新。最新版make_averager的正确实现如下:

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关键字。如果要实现上面的功能需要变通的方法。基本上,这种处理方式是把内部函数需要修改的变量(如count和total)存储为可变对象(如字典或简单的实例)的元素或属性,并且把那个对象绑定给一个自由变量。
至此,我们了解了Python闭包,接下来可以使用嵌套函数正式实现装饰器了。


欢迎关注微信公众号:CodeWorks
问题或建议,请公众号留言,欢迎非抬杠式讨论

相关文章

  • 简谈Python3关键字nonlocal使用场景

    下面是之前提过的有待提升效率的计算移动平均的方法: 我们在文章简谈Python闭包中设计的计算移动平均的方法效率并...

  • python 3 关键字

    查看python3的所有关键字(其中nonlocal是python3新增) 检查字符串是否为关键字,返回True或...

  • 平常注意到的一些python知识点

    1、global关键字用来在函数或其他局部作用域中使用全局变量,nonlocal关键字用来在函数或其他作用域中使用...

  • 可变数据

    Python3可以使用nonlocal 在父级框架中声明子框架中的变量 Python中可以使用字典将多个函数绑定在...

  • python关键字nonlocal和global的区别

    关键字nonlocal:是python3.X中出现的,所以在python2.x中无法直接使用. python引用变...

  • Python基础部分(三)

    输入与输出 在python3中,我们使用input()关键字输入数据,使用print()关键字输出数据: 运算符 ...

  • 函数的嵌套和作用域,闭包,装饰器

    函数的嵌套定义 nonlocal关键字的作用 在有嵌套的函数中,如果我们内部的函数使用外部的变量的时候,如果只是访...

  • python3 的 nonlocal

    看代码: 结果是: 记录1:这个很好理解,内嵌函数的x屏蔽了外围函数的x;是两个不同的x; 记录2:在Python...

  • Python3.0中nonlocal关键字和python2.xl

    python 应用小知识,Python3.0中nonlocal关键字和python2.xlist或dict。希望小...

  • 将pip安装到Python3目录下

    应用场景 默认mac上已经安装了 python2; 而我又安装了 python3,并使用 python3; 安装了...

网友评论

      本文标题:简谈Python3关键字nonlocal使用场景

      本文链接:https://www.haomeiwen.com/subject/bgdggctx.html