python 闭包的作用_python中对闭包的理解
运行环境声明:本人的代码在sublime text 3中写的,可以Ctrl+b运行。python版本是python3.6。如果您直接运行的,请自觉加入if __name__ == '__main__'
认识闭包之前
在认识闭包之前,其实还应该知道,什么是嵌套函数(nested functions),什么是non-local变量(non-local variables)。
1.嵌套函数
嵌套函数:定义在其他函数内部的函数。嵌套函数可以访问enclosing scope的变量。enclosing scope是指一个封闭的作用域。在这里主要指定义嵌套函数的函数的作用域。即,嵌套函数可以访问外层变量。
2.non-local变量
要讲non-local变量,这里就会涉及python引用变量的顺序:
当前作用域局部变量->外层作用域变量->当前模块中的全局变量->python内置变量(这里可以看到当前作用域的变量的执行优先级别最高)
在变量同名的情况下,执行优先级别高的的变量会把优先级别低的屏蔽掉。如:
s = 1 #全局变量
def outer_function():
s = 2 # 外层作用域变量
def iner_function():
s = 3 #当前作用域局部变量
print(s)
iner_function()
outer_function()
输出结果为3
注意:我们是以iner_function函数为参考点展开讨论变量的作用域的。
上面输出可以看到,当前作用域局部变量将外层作用域变量和当前模块全局变量屏蔽掉了。
这里我假设有两个应用场景:
假如我要在当前作用域访问全局变量怎么办?(可以用gobal关键字)
假如我要在当前作用域访问外层作用域局部变量怎么办?(可以用nonlocal关键字)
global关键字:global关键字用来在函数或其他局部作用域中使用全局变量。但是如果不修改全局变量也可以不使用global关键字。
还是用刚才的例子:
s = 1 #全局变量
def outer_function():
def iner_function():
print(s)
iner_function()
outer_function()
输出结果为1
因为不对s进行修改,且iner_function函数内部也没有局部变量。因此可以在不声明global的情况下访问到s。
但现在我要修改s的值:
s = 1 #全局变量
def outer_function():
def iner_function():
s += 1
print(s)
iner_function()
outer_function()
出现错误:UnboundLocalError: local variable 's' referenced before assignment
此时应该用global声明s是全局变量:
s = 1 #全局变量
def outer_function():
def iner_function():
global s
s += 1
print(s)
iner_function()
outer_function()
print(s)
输出结果为:
2
2
[Finished in 0.2s]
应该注意到,在修改s的值时,全局变量s的值也变了。也就是说,inner_function函数中的s和全局变量s是同一个变量。
nonlocal关键字:nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量。
s = 1
def outer_function():
s = 2 # 外层作用域变量
def iner_function():
nonlocal s
s += 1
print(s)
iner_function()
print("The value of s in outer_function:", s)
outer_function()
print("The global value s:", s)
输出结果为:
3
The value of s in outer_function: 3
The global value s: 1
[Finished in 0.2s]
这里应该注意到nonlocal声明的变量s改变之后,并不对全局变量产生影响。
若要参考更多关于变量作用域访问问题,请看这里
什么是闭包?
好了,前面说了一大堆,现在开始看看,什么是闭包!
闭包(closure)是函数式编程的重要的语法结构,是词法闭包(Lexical Closure)的简称。是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境。
闭包是一个存储了函数及其环境的一个记录(record):一个将函数的自由变量和“值”(或者“变量名所绑定的引用”)关联起来的映射(mapping),自由变量是指在嵌套函数内使用但却是在定义嵌套函数的函数内定义的变量。
闭包不像普通函数,它允许通过“闭包复制到的值或者引用”来访问这些要被访问的对象的值,即使函数的调用发生在这些值的作用域外。
def outerFunction(text):
text = text
def innerFunction():
print(text)
return innerFunction # Note we are returning function WITHOUT parenthesis
myFunction = outerFunction('Hey!')
myFunction()
输出是:hey!
通过观察,我们发现,闭包帮助我们在一个函数的作用域外调用这个函数。即,我们通过调用outerFunction函数来间接调用了inerFunction函数。要知道,我们是无法直接在inerFunction函数的作用域外调用它自己的。从另一个层面来讲,我们通过闭包间接扩大了inerFunction函数的作用域!
另外当执行完myFunction = outerFunction('Hey!')语句时,实际上是将一个闭包返回给myFunction。outerFunction('Hey!')执行完之后,实际上outerFunction函数里的变量text已经被销毁。但这里闭包已经将text记住了,所以我们执行myfunction()时,还是可以访问到text的内容!
什么时候或者为什么使用闭包?
将闭包作为一个返回函数,可以做到数据隐藏,从而减少对全局变量的使用。
当我们的代码只是要有很少的函数时,使用闭包是一个非常有效的方式。当有多个函数时,还是用类。
一个经典错误
flist = []
for i in xrange(3):
def func(x): return x * i
flist.append(func)
for f in flist:
print f(2)
期待输出"0 2 4",但这个代码输出的是:"4 4 4"。
解释:flist.append(func)这句语句将每3个闭包(函数func)存储在列表flist中。这没错。但是,要注意到,在整个for循环for i in xrange(3):中,i的值并没有被销毁,而i的值是不断增加的,在这个循环中,每一个闭包对i的引用并没有“被切断”。到退出for循环时,i被销毁,同时,3个闭包(func函数)都对这个相同的i值进行了独立的存储。这里三个闭包是独立的没问题,但每一个闭包在最后存储i的时候,i的值已经是2了。
怎么避免这种错误呢?
看解决方法:
flist = []
for i in xrange(3):
def funcC(j):
def func(x): return x * j
return func
flist.append(funcC(i))
for f in flist:
print f(2)
这里可以轻易看到,当执行第一次循环时,i的值是0,return func执行之后,实际上funcC函数里的变量i就已经被销毁了,在销毁的那瞬间,第一个闭包就记住了第一个i的值。第二,三个闭包原理相同。可以参考here
到最后
参考,英文水平和表达能力有限,建议大家看文中我给出的连接。我是参考他们的文章写的。
版权:保留所有权,转载注明出处。
python 闭包的作用_python中对闭包的理解相关推荐
- python闭包应用实例_Python中的闭包详细介绍和实例
一.闭包 来自wiki: 闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数.这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外 ...
- python斜杠作用_Python中正反斜杠(‘/’和‘\’)的意义与用法
刚刚在学习些测试报告的时候,出现一个路径的问题,找了很久的原因,竟然是少了一个反斜杠引起的,在此顺便记录一下正反斜杠的作用. 在Python中,记录路径时有以下几种写法,如:(大家都知道\n是换行的意 ...
- python中括号的作用_python中中括号
广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 在python语言中最常见的括号有三种,分别是:小括号().中括号:代表list ...
- python异常处理的作用_Python 中的异常处理方式
封面图片来源:沙沙野 异常处理什么是异常处理?Python 解释器检测到错误就会触发异常,或者程序员自己触发异常 程序中编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关) ...
- python变量的作用_Python中的变量
Python中的变量是用来表示一个值的标识符.变量代表了计算机内存中的一个地址.变量允许在程序中访问其他对象,调用函数或执行其他运算. 1.变量命名规则 变量是Python中的标识符,它应该遵循标识符 ...
- python signal模块作用_Python中的signal模块和Ctrl+C操作
Python中的signal模块处理OS级别的信号.例如Ctrl+C会进程发送信号. Linux上查看信号的方法: [appadmin@BJLTPGPLM1007T ~]$ kill -l 1) SI ...
- python pyc文件作用_Python中pyc文件的用途
什么是pyc文件 pyc是一种二进制文件,是由py文件经过编译后,生成的文件,是一种byte code,py文件变成pyc文件后,加载的速度有所提高,而且pyc是一种跨平台的字节码,是由python的 ...
- python算法和数据结构_Python中的数据结构和算法
python算法和数据结构 To 至 Leonardo da Vinci 达芬奇(Leonardo da Vinci) 介绍 (Introduction) The purpose of this ar ...
- python中闭包的作用_Python闭包及其作用域
Python闭包及其作用域 关于Python作用域的知识在python作用域有相应的笔记,这个笔记是关于Python闭包及其作用域的详细的笔记 如果在一个内部函数里,对一个外部作用域(但不是全局作用域 ...
最新文章
- 【青少年编程(第29周)】8月份的青少年编程组队学习结营了!
- xss防御方法base64_XSS 防御方法总结
- sizeof和gcvt转换双精度函数的函数不是小结的小结
- 如何打开.etl文件?
- 【CSS 伪类】顺序
- P2717-寒假作业【逆序对,树状数组】
- linux rar命令没找到,Linux没有rar解压命令
- Hooks解决了什么问题?
- hibernate oracle 读写分离_ASP.NET CORE 国产最火前后端完全分离框架BCVP
- ASP.NET MVC5 + EF6 + BootStrap 实战系列教程
- 物联网领域不断扩展,ATT很“兴奋”
- Linux内核那些事之连接跟踪
- python-83:公务员时间源码 V-0.1
- 那些所倚靠的利器记载
- spring框架:(二)bean标签中的scop、生命周期以及注入方式
- oracle rowid与rownum的使用
- CLIP4Clip: An Empirical Study of CLIP for End to End Video Clip Retrieval
- 2019计算机专业保研经历(清华、南大、上交)
- EasyMesh认证即基于Multi-AP标准
- 从0到1:美团端侧CDN容灾解决方案