python3 平均值_简谈Python3关键字nonlocal使用场景

7f153f69cc326e04339eaf11bf7a25b2.png

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

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

我们在文章简谈Python3中的闭包中设计的计算移动平均的方法效率并不高,原因是我们存储了所有的历史数据在列表中,然后在每次调用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闭包,接下来可以使用嵌套函数正式实现装饰器了。

推荐阅读:

Mr.汪汪汪:简述Python中变量作用域的规则​zhuanlan.zhihu.com
zhihu-card-default.svg
Mr.汪汪汪:简谈Python3中的闭包​zhuanlan.zhihu.com
zhihu-card-default.svg
Mr.汪汪汪:浅析Python中列表操作之*和*=​zhuanlan.zhihu.com
zhihu-card-default.svg
Mr.汪汪汪:浅析Python中的列表和元组​zhuanlan.zhihu.com
zhihu-card-default.svg
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程概述教会学员快速学会python数据分析,覆盖python基础,pandas,seaborn,matplotlib,SQL,sqlite,lambda等知识。课程是数据科学家居家必备的军火库。课程定期更新,大部分视频分辨率支持2K超清,学员可以看清每一行代码。 适合人群python数据科学从业人员,数据分析师,统计 学习计划和方法1.每天保证1-2个小时学习时间,预计7-15天左右可以学习完整门课程(不同基础学生时间差异较大)。2.每节课的代码实操要保证,建议不要直接复制粘贴代码,自己实操一遍代码对大脑记忆很重要,有利于巩固知识。3.第二次学习时要总结上一节课内容,必要时做好笔记,加深大脑理解。4.不懂问题要罗列出来,先自己上网查询,查不到的可以咨询老师。 作者介绍Toby,持牌照金融公司担任模型验证专家,国内最大医药数据中心数据挖掘部门负责人!和清华大学出版社,重庆儿科医院,中科院教授,赛柏蓝保持慢病数据挖掘项目合作!管理过欧美日中印巴西等国外药典数据库,马丁代尔数据库,FDA溶解度数据库,临床试验数据库,WHO药物预警等数据库。原创公众号(python风控模型) 课程概述教会学员快速学会python数据分析,覆盖python基础,pandas,seaborn,matplotlib,SQL,sqlite,lambda等知识。课程是数据科学家居家必备的军火库。课程定期更新,大部分视频分辨率支持2K超清,学员可以看清每一行代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值