python中闭包必须存在于什么关系的函数中,python构成闭包的条件
1.定义
闭包是函数式编程的重要语法结构,函数式编程是一种编程范式(而面向过程编程和面向对象编程也是编程范式)。在面向过程的编程中,我们见过function);在面向对象编程中,我们见过object。函数和对象的根本目的是以逻辑的方式组织代码,提高代码的可重用性。闭包也是一种组织代码的结构,也提高了代码的重用性。
不同的编程语言有不同的方法来实现闭包。在python中,闭包用形式来表示。如果外部作用域(而不是全局作用域)中的变量在内部函数中被引用,那么内部函数被认为是一个闭包。
例如:
外部定义(x):
内部定义(y):
返回x y
返回内部
一个
2
三
四
五
结合这个简单的代码和定义来说明闭包:
Inner(y)就是这个内部函数,引用外部作用域(但不在全局作用域)的变量:X是被引用的变量,如果X在外部作用域outer但不在全局作用域,那么这个内部函数Inner就是一个闭包。
稍微详细一点的解释是,闭包=功能块定义一个功能时的环境。inner是功能块,X是环境。当然,这个环境可以有很多,不止一个简单的x。
内部函数在外部函数中定义。内部函数访问外部函数的(参数)变量,并将内部函数作为返回值返回给外部函数。
a=外部(2)
打印(函数:,a)
打印(结果:,a(3))
一个
2
三
a是上面代码中的一个函数,代码的执行结果是:
由此,不难看出,A是函数inner而不是outer。这有点绕,但也不难理解,因为return返回的是内部函数。
print(a.func_name ,a.func_name)
一个
输出是:
调用函数A,结果是传入参数值的相加。
上面和这句话一样:print(result:,outer(2)(3))
2.使用闭包时需要注意什么
2.1闭包不能修改外部函数的局部变量。
如果innerFunc可以修改x的值,那么x的值会前后变化,但结果是:
x的值在innerFunc中改变了,但在outerFunc中没有改变。
我们再举一个例子。
2.2闭包不能直接访问外部函数的局部变量。
定义外部():
x=5
Def inner():上面一行中的# X是相对于内部函数的函数外部的局部变量(非全局变量)。
x *=x
返回x
返回内部
外部()()
一个
2
三
四
五
六
七
八
运行时会出现错误:
解决方案是:
1.在python3之前,没有直接的解决方法,只能通过容器类型间接解决,因为容器类型不存储在堆栈空间中,可以被内部函数访问。
定义外部():
x=[5]
内部定义():
x[0] *=x[0]
返回x[0]
返回内部
print(outer()()) #25
一个
2
三
四
五
六
七
八
2.python3由nonlocal关键字解决,该关键字显式指定A不是闭包的局部变量。
定义外部():
x=5
内部定义():
非局部x #将x声明为非局部变量
x *=x
返回x
返回内部
print(outer()())
一个
2
三
四
五
六
七
八
九
2.3python循环不包含域的概念。
当引入python闭包时,经常会提到另一种容易出错的情况。我从来不认为这个错误与闭包有很大关系,但它确实是python函数式编程中容易犯的错误。我不妨在这里介绍一下。先看下面的代码。
对于范围(3)中的I:
打印I
一个
2
三
这种循环语句经常出现在程序中。Python的问题是,当循环结束时,循环体中的临时变量I不会被销毁,而是继续存在于执行环境中。python的另一个现象是,python函数在执行时只在函数体中寻找变量值。
flist=[]
对于范围(3)中的I:
def foo(x):打印x i
对于flist中的f:
女(2)
一个
2
三
四
五
六
可能有人会觉得这段代码的执行结果应该是2,3,4。但实际结果是4,4,4。loop python中没有域的概念。flist在图像列表中加入func时,并没有保存I的值,只是在执行f(2)时取它。这时候循环已经结束,I的值是2,所以结果都是4。
解决方法也很简单,重写函数的定义就行了。
对于范围(3)中的I:
def foo(x,y=i): print x y
flist.append
一个
2
三
四
3.闭包的功能
说到这里,有人要问了,这种封闭在实际开发中有什么用?闭包主要用于功能开发。这里是闭包的两个主要用途。
1.目的:执行闭包后,仍然可以保持当前的运行环境。
例如,如果您希望某个函数的每次执行结果都基于该函数的上次执行结果。我用一个类似棋盘游戏的例子来说明一下。假设棋盘大小为50*50,左上角是坐标系(0,0)的原点,我需要一个接收两个参数的函数,分别是方向和步长。这个函数控制棋子的移动。棋子移动的新坐标除了方向和步长,当然必须以原坐标为基础,可以使用闭包来保持棋子的原坐标。
原点=[0,0]
legal_x=[0,50]
legal_y=[0,50]
定义创建(位置=原点):
定义玩家(方向,步):
#这里首先要判断参数方向和步长的合法性,比如方向不能走对角线,步长不能为负数等。
#然后,需要判断新生成的X、Y坐标的合法性。这里主要想介绍一下闭包,就不详细写了。
new_x=pos[0]方向[0]*步长
new_y=pos[1]方向[1]*步长
pos[0]=new_x
pos[1]=new_y
#注意!这里不能写成pos=[new_x,new_y],因为参数变量不能修改,pos[]是容器类的解。
退货位置
返回播放器
Player=create() #以原点为起点创建一个棋子玩家。
Print ([1,0],10) #在X轴正方向移动10步
Print ([0,1],20) #沿Y轴正方向移动20步
Print player([-1,0],10) #在X轴的负方向移动10步
一个
2
三
四
五
六
七
八
九
10
11
12
13
14
15
16
17
18
19
输出是:
[10, 0]
[10, 20]
[0, 20]
一个
2
三
目的:闭包可以根据外部作用域的局部变量得到不同的结果。
这有点像配置函数。我们可以修改外部变量,闭包根据这个变量显示不同的函数。比如有时候我们需要分析一些文件的专用线,先把这些专用线提取出来。
def make_filter(保留):
定义过滤器(文件名):
file=open(文件名)
lines=file.readlines()
file.close()
filter _ doc=[I for I in lines if keep in I]
返回过滤器_文档
返回_过滤器
一个
2
三
四
五
六
七
八
如果我们需要获取文件“result.txt”中带有关键字“pass”的行,我们可以像这样使用示例程序。
filter=make _ filter( pass )filter _ result=filter( result . txt )
一个
2
以上两种使用场景,用面向对象也很容易实现,但是在用Python进行函数式编程时,闭包对于数据持久化和根据配置不同的功能是很有帮助的。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。