一、 概念
闭包(Closure)又称词法闭包(Lexical Closure)或函数闭包(function closures),闭包与函数嵌套有关,在《第5.5节 函数递归、嵌套及样例》中老猿介绍了函数嵌套,函数中嵌套的函数称为嵌套函数、外层的函数称为封闭函数。闭包简单来说就是一个嵌套函数中引用了封闭函数定义的变量,并且该函数可以在其定义环境外即封闭函数外被执行。这样的嵌套函数我们称之为闭包。嵌套函数使用的封闭函数的变量称为自由变量。
在闭包的情况下,在调用封闭函数后,会将嵌套函数返回给调用方,调用结束后,封闭函数执行结束,其执行时的自由变量传递给了嵌套函数保存,而嵌套函数被调用方保存,意味着调用方获取了嵌套函数及其调用时自由变量的值,意味着嵌套函数与封闭函数脱离了关系独立存在。因此闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
要创建闭包,必须满足以下条件:
• 必须包含一个嵌套函数
• 嵌套函数必须引用封闭函数中定义的自由变量,在引用前需用nonlocal关键字进行声明
• 封闭函数的调用结果必须将嵌套函数作为其返回值
二、 闭包的好处
- 取代硬编码中的常量
由于闭包中可以通过封闭函数的自由变量传递值给闭包函数,而闭包函数中该自由变量的值可以保持不变,这样可以不使用常量来实现,又具有灵活性,通过不同的闭包实例使用不同的自由变量值。 - 避免使用全局值,并提供某种形式的数据隐藏
在闭包实例中自由变量可以在脱离封闭函数的情况下保持不变,从而取代了全局变量的作用。 - 实现面向对象
闭包可以允许不同的实例实际执行存在差异,这样可以在不同类中调用同一封闭函数传递不同自由变量的值而实现不同的执行效果,这样调用方无需关注是通过哪个类进行调用,从而实现了一定程度的封装。
三、 案例
>>> def cal(op):
def calop(op1,op2):
nonlocal op
if op=='+':return op1+op2
elif op=='-':return op1-op2
elif op=='*':return op1*op2
elif op=='/':return op1/op2
else: raise ValueError('运算符必须是+-*/中的一个')
return calop
>>> add =cal('+')
>>> minus=cal('-')
>>> add(1,2)
3
>>> minus(1,2)
-1
>>>
四、 补充说明
- 所有函数对象都有一个 closure 属性,如果这个函数是一个闭包函数,那么会返回的是一个由 cell 对象组成的元组。cell 对象具有 cell_contents 属性,存储了闭包中的自由变量。这也解释了为什么局部变量在脱离函数之后,还可以在函数之外被访问,因为它存储在了闭包的 cell_contents 中;
- 闭包之所以又称为词法闭包,是因为自由变量的作用域在定义时确认了,而不是在执行时决定。这符合词法作用域(Lexical Scoping)的概念。词法作用域取决于源码,通过静态分析就能够确定,因此,词法作用域也叫做静态作用域;
- Python中闭包最常用的场景就是装饰器,关于装饰器在此不展开介绍,将在中高级课程部分再介绍。
老猿Python,跟老猿学Python!
博客地址:https://blog.csdn.net/LaoYuanPython
请大家多多支持,点赞、评论和加关注!谢谢!