“ 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中体现就如下面截图所示。
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
【结语】欢迎大家后台留言讨论,说出感兴趣内容!如果觉得有帮助,请您点赞、分享,您的肯定是小编的最大动力!