外部函数能修改闭包内的变量_修饰器与闭包(2)

本文介绍了Python中的闭包概念,详细解释了闭包如何保留外部变量的绑定。通过示例展示了当内部函数试图修改不可变类型变量时引发的错误,并引出了nonlocal关键字的作用,nonlocal使得内部函数能够更新外部函数的不可变类型变量。同时,对比了global关键字用于修改全局变量的情况。最后,讨论了如何在Python中合理使用nonlocal和global来优化代码逻辑。
摘要由CSDN通过智能技术生成

 No rule without an exception

闭包指的是延伸了作用域的函数,这种函数可以调用的变量包括函数体内定义的局部变量和不在函数定义体内的自由变量。本质上,闭包是一种函数,它保留了定义函数时存在的自由变量的绑定。

01

闭包的范围

既然闭包指的是延伸了作用域的函数,那么我们先了解一下没有延伸作用域的函数。

# 示例 1-1>>> def make_average():...     count = 0...     total = 0...     def average(new_value):...         count += 1...         total += new_value...         return total / count...     return average...

在示例1-1中定义了一个make_average()函数,返回值是内部函数average()。内部函数average()的返回值是一个简单的平均值计算结果。如果我们调用这个函数,结果会提示示例1-2中的错误。

# 示例 1-2>>> avg = make_average()>>> avg(10)Traceback (most recent call last):  File "", line 1, in   File "", line 5, in averageUnboundLocalError: local variable 'count' referenced before assignment

示例1-2中错误信息是指局部变量"count"被引用的时候还没有被定义。显然count变量是定义在函数average()函数之外,这看起来似乎也可以理解。但是如果按照示例1-3中的写法,即便是引用了外部变量也不会报错。

# 示例 1-3>>> def make_average():...     series = []...     def average(new_value):...         series.append(new_value)...         total = sum(series)...         return total/len(series)...     return average... >>> avg = make_average()>>> avg(10)10

同样是average()函数调用了外部变量,示例1-3代码可以正确运行的原因是因为只调用了series的append()函数,并传递对应值给sum和len,这里利用的是列表的可变性。但是数字、字符串、元组这些属于不可变类型,只能读取,无法更新。一旦尝试重新绑定,如count = count +1,则会创建局部变量count,但是count在之前有没有定义过,这就是示例1-2报错的原因。对应地,闭包在示例1-3中体现就如下面截图所示。

9b460f4fbc04b2549d2d1bfa9723d2b2.png

02

nonlocal和global

示例1-2代码虽然运行出错,但是在逻辑上应该是效率更高的,只需要存在总数和元素个数即可。而示例1-3代码需要把所有值存储在列表中,然后再每一次调用average()时使用sum求和。为解决这一矛盾,Python3中引入了nonlocal声明关键字。被nonlocal关键字修饰的变量也会变为自由变量,即可以对不可变类型进行赋值,闭包中保存的绑定会更新。具体如示例2-1所示。

# 示例 2-1>>> def make_average():...     count = 0...     total = 0...     def average(new_value):...         nonlocal count, total...         count += 1...         total += new_value...         return total/count...     return average... >>> avg = make_average()>>> avg(10)10.0

nonlocal关键字是在函数内嵌套了内部函数,并且内部函数需要调用并修改外部函数变量时使用。与之功能相似的关键字还有global。如果没有使用global修饰,函数内部只能访问外部变量,而不能修改。global关键字可以将局部变量的作用域提升为全局变量,进而可以修改全局变量。

# 示例 2-2>>> average(10)10.0>>> def average(num):...     a = 200...     return a/num... >>> average(10)20.0>>> print(a)100

示例2-2中可以看出函数average修改的变量a属于局部变量,再打印变量a时仍然为100,加上global则可以进行修改。

# 示例2-3>>> def average(num):...     global a...     a = 200...     return a/num... >>> average(10)20.0>>> print(a)200

【结语】欢迎大家后台留言讨论,说出感兴趣内容!如果觉得有帮助,请您点赞、分享,您的肯定是小编的最大动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值