什么是闭包?闭包有什么用?为什么要用闭包?

2024-01-21 04:18
文章标签 闭包 要用

本文主要是介绍什么是闭包?闭包有什么用?为什么要用闭包?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

什么是闭包?闭包有什么用?为什么要用闭包?

今天我们就带着这3个问题来一步一步认识闭包。闭包和函数紧密联系在一起,介绍闭包前有必要先介绍一些背景知识,诸如嵌套函数、变量的作用域等概念

newone就是闭包函数

作用域

作用域是程序运行时变量可被访问的范围,定义在函数内的变量是局部变量,局部变量的作用范围只能是函数内部范围内,它不能在函数外引用。

Python
def foo(): num = 10 # 局部变量 print(num) # NameError: name 'num' is not defined
1
2
3
def foo ( ) :
num = 10 # 局部变量
print ( num ) # NameError: name 'num' is not defined

定义在模块最外层的变量是全局变量,它是全局范围内可见的,当然在函数里面也可以读取到全局变量的。例如:

Python
num = 10 # 全局变量 def foo(): print(num) # 10
1
2
3
num = 10 # 全局变量
def foo ( ) :
print ( num ) # 10

嵌套函数

函数不仅可以定义在模块的最外层,还可以定义在另外一个函数的内部,像这种定义在函数里面的函数称之为嵌套函数(nested function)例如:

Python
def print_msg(): # print_msg 是外围函数 msg = "zen of <span class="wp_keywordlink"><a href="http://www.168seo.cn/python" title="python">python</a></span>" def printer(): # printer是嵌套函数 print(msg) printer() # 输出 zen of <span class="wp_keywordlink"><a href="http://www.168seo.cn/python" title="python">python</a></span> print_msg()
1
2
3
4
5
6
7
8
9
10
def print_msg ( ) :
# print_msg 是外围函数
msg = "zen of python"
def printer ( ) :
# printer是嵌套函数
print ( msg )
printer ( )
# 输出 zen of python
print_msg ( )

对于嵌套函数,它可以访问到其外层作用域中声明的非局部(non-local)变量,比如代码示例中的变量 msg 可以被嵌套函数 printer 正常访问。

那么有没有一种可能即使脱离了函数本身的作用范围,局部变量还可以被访问得到呢?答案是闭包

什么是闭包

函数身为第一类对象,它可以作为函数的返回值返回,现在我们来考虑如下的例子:

Python
def print_msg(): # print_msg 是外围函数 msg = "zen of <span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/python" title="View all posts in python" target="_blank">python</a></span>" def printer(): # printer 是嵌套函数 print(msg) return printer another = print_msg() # 输出 zen of <span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/python" title="View all posts in python" target="_blank">python</a></span> another()
1
2
3
4
5
6
7
8
9
10
11
def print_msg ( ) :
# print_msg 是外围函数
msg = "zen of python"
def printer ( ) :
# printer 是嵌套函数
print ( msg )
return printer
another = print_msg ( )
# 输出 zen of python
another ( )

这段代码和前面例子的效果完全一样,同样输出 "zen of python"。不同的地方在于内部函数 printer 直接作为返回值返回了。

一般情况下,函数中的局部变量仅在函数的执行期间可用,一旦 print_msg() 执行过后,我们会认为 msg变量将不再可用。然而,在这里我们发现 print_msg 执行完之后,在调用 another 的时候 msg 变量的值正常输出了,这就是闭包的作用,闭包使得局部变量在函数外被访问成为可能。

看完这个例子,我们再来定义闭包,维基百科上的解释是:

在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。
这里的 another 就是一个闭包,闭包本质上是一个函数,它有两部分组成,printer 函数和变量 msg。闭包使得这些变量的值始终保存在内存中。

闭包,顾名思义,就是一个封闭的包裹,里面包裹着自由变量,就像在类里面定义的属性值一样,自由变量的可见范围随同包裹,哪里可以访问到这个包裹,哪里就可以访问到这个自由变量。

为什么要使用闭包

闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。这一点与面向对象编程是非常类似的,在面对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

一般来说,当对象中只有一个方法时,这时使用闭包是更好的选择。来看一个例子:

Python
def adder(x): def wrapper(y): return x + y return wrapper adder5 = adder(5) # 输出 15 adder5(10) # 输出 11 adder5(6)
1
2
3
4
5
6
7
8
9
10
def adder ( x ) :
def wrapper ( y ) :
return x + y
return wrapper
adder5 = adder ( 5 )
# 输出 15
adder5 ( 10 )
# 输出 11
adder5 ( 6 )

这比用类来实现更优雅,此外装饰器也是基于闭包的一中应用场景。

所有函数都有一个 __closure__属性,如果这个函数是一个闭包的话,那么它返回的是一个由 cell 对象 组成的元组对象。cell 对象的cell_contents 属性就是闭包中的自由变量。

Python
>>> adder.__<span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/closure" title="View all posts in closure" target="_blank">closure</a></span>__ >>> adder5.__<span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/closure" title="View all posts in closure" target="_blank">closure</a></span>__ (<cell at 0x103075910: int object at 0x7fd251604518>,) >>> adder5.__closure__[0].cell_contents 5
1
2
3
4
5
>>> adder . __closure__
>>> adder5 . __closure__
( < cell at 0x103075910 : int object at 0x7fd251604518 > , )
>>> adder5 . __closure__ [ 0 ] . cell _contents
5

这解释了为什么局部变量脱离函数之后,还可以在函数之外被访问的原因的,因为它存储在了闭包的 cell_contents中了。

 

引用:https://foofish.net/python-closure.html




  • zeropython 微信公众号 5868037 QQ号 5868037@qq.com QQ邮箱

这篇关于什么是闭包?闭包有什么用?为什么要用闭包?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/628349

相关文章

JavaScript深入理解闭包

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 一、变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域。 变量的作用域无非就是两种:全局变量和局部变量。 Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。 Js代码   var n=999;   function f1

【JavaScript】在循环内使用闭包

================== 基本循环语句 ==================for (var i = 0; i < 5; i++) {console.log(i);}console.log(i);//这个大家应该很快就知道了,012345================== setTimeout与var语句的for循环 ==================for (var i

python闭包的作用

python闭包的作用 Python中的闭包是一种强大的编程概念,它在处理函数和作用域时提供了灵活性和便利性。下面是闭包的一些主要作用和应用: 1. 封装数据和函数 闭包可以将数据和操作这些数据的函数封装在一起,使得外部无法直接访问这些数据。这有助于创建数据的私有性。 def make_counter():count = 0def counter():<

【HDU】1317 XYZZY spfa判负环+floyd求传递闭包

传送门:【HDU】1317 XYZZY 题目分析:首先我们可以用spfa判最长路上是否有正权环,但是有正权环却不等价于能到达终点。这是我们还需要判断是否能从正权环中走到终点,这个可以用传递闭包搞定。如果没有正权环就看是否能从起点到终点就好了。 代码如下: #include <cstdio>#include <cstring>#include <algorithm>

前端组件化(一) 函数闭包 简单版

实现功能: 输入几个字, 就实时显示几个字 截图: 作用域隔离 为了使整个代码的作用域清晰明了, 封装成textCont 函数 <!DOCTYPE HTML><html><head><title>单通道数据流</title></head><body><input type="text" id="J_inp"><span id="J_text"></span></body><script sr

[Python]闭包与装饰器

闭包与装饰器 闭包: ​ python的一种独有写法,可以实现:对外部函数的局部变量进行’临时’存储 作用: ​ 可以"延长"函数内 局部变量的生命周期. 构成条件: 1. 有嵌套. 外部函数内要嵌套 内部函数.2. 有引用. 在内部函数中使用 外部函数的变量.3. 有返回. 在外部函数中, 返回 内部函数名, 即: 内部函数对象 格式def 外部函数

初探swift语言的学习笔记三(闭包-匿名函数)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/29353019 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! 很多高级语言都支持匿名函数操作,在OC中的block也为大家所熟悉,然面在swift里好像是被

深入理解JavaScript系列(16):闭包(Closures)

介绍 本章我们将介绍在JavaScript里大家经常来讨论的话题 —— 闭包(closure)。闭包其实大家都已经谈烂了。尽管如此,这里还是要试着从理论角度来讨论下闭包,看看ECMAScript中的闭包内部究竟是如何工作的。 正如在前面的文章中提到的,这些文章都是系列文章,相互之间都是有关联的。因此,为了更好的理解本文要介绍的内容,建议先去阅读第14章作用域链和第12章变量对象。 英

Javascript归纳与总结——this指向及其改变、new关键字与原型链、异步、闭包和函数防抖与节流

this指向及其改变 普通函数在调用时,this为obj.obj1.fun(),this->obj1,箭头函数在声明定义时this->obj。 Javascript中bind、call、apply區別-CSDN博客 new关键字与原型链  从原型链视角解读VueComponent与Vue关系_vue中重要的原型链关系-CSDN博客 prototype这个属性只有函数对象才有!(构造)

python基础-闭包、装饰器

闭包 什么是闭包? 内部函数引用了外部函数的变量 看下面的代码 def f(b):def f1():print(b)f1()print(f1.__closure__)f(1) 输出如下: E:\python\python_sdk\python.exe E:/python/py_pro/demo.py1(<cell at 0x01406390: int object at 0x56A