python中闭包,闭包的实质

 

https://www.cnblogs.com/Lin-Yi/p/7305364.htmlhtml

闭包这个概念好难理解,身边朋友们好多都稀里糊涂的,稀里糊涂的林老冷但愿写下这篇文章可以对稀里糊涂的伙伴们有一些帮助~python

 

请你们跟我理解一下,若是在一个函数的内部定义了另外一个函数,外部的咱们叫他外函数,内部的咱们叫他内函数。编程

闭包: 闭包

  在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,而且外函数的返回值是内函数的引用。这样就构成了一个闭包。编程语言

通常状况下,在咱们认知当中,若是一个函数结束,函数的内部全部东西都会释放掉,还给内存,局部变量都会消失。可是闭包是一种特殊状况,若是外函数在结束的时候发现有本身的临时变量未来会在内部函数中用到,就把这个临时变量绑定给了内部函数,而后本身再结束。函数

  很晦涩很难理解啊!!咱们来看一段代码^.^spa

复制代码
 1 #闭包函数的实例
 2 # outer是外部函数 a和b都是外函数的临时变量
 3 def outer( a ):
 4     b = 10
 5     # inner是内函数
 6     def inner():
 7         #在内函数中 用到了外函数的临时变量
 8         print(a+b)
 9     # 外函数的返回值是内函数的引用
10     return inner
11 
12 if __name__ == '__main__':
13     # 在这里咱们调用外函数传入参数5
14     #此时外函数两个临时变量 a是5 b是10 ,并建立了内函数,而后把内函数的引用返回存给了demo
15     # 外函数结束的时候发现内部函数将会用到本身的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
16     demo = outer(5)
17     # 咱们调用内部函数,看一看内部函数是否是能使用外部函数的临时变量
18     # demo存了外函数的返回值,也就是inner函数的引用,这里至关于执行inner函数
19     demo() # 15
20 
21     demo2 = outer(7)
22     demo2()#17
复制代码

 

从上面例子是我写的一个最简单的很典型的闭包。我估计若是是初学的小伙伴,可能不少名词都不明白是什么意思,不要紧,我把这些名词按照本身的理解去解释一下~指针

1 外函数返回了内函数的引用:code

  引用是什么?在python中一切都是对象,包括整型数据1,函数,实际上是对象。htm

  当咱们进行a=1的时候,实际上在内存当中有一个地方存了值1,而后用a这个变量名存了1所在内存位置的引用。引用就好像c语言里的指针,你们能够把引用理解成地址。a只不过是一个变量名字,a里面存的是1这个数值所在的地址,就是a里面存了数值1的引用。

  相同的道理,当咱们在python中定义一个函数def demo():  的时候,内存当中会开辟一些空间,存下这个函数的代码、内部的局部变量等等。这个demo只不过是一个变量名字,它里面存了这个函数所在位置的引用而已。咱们还能够进行x = demo, y = demo, 这样的操做就至关于,把demo里存的东西赋值给x和y,这样x 和y 都指向了demo函数所在的引用,在这以后咱们能够用x() 或者 y() 来调用咱们本身建立的demo() ,调用的实际上根本就是一个函数,x、y和demo三个变量名存了同一个函数的引用。

  不知道你们有没有理解,很晦涩,但愿我说明白了我想表达的。

  有了上面的解释,咱们能够继续说,返回内函数的引用是怎么回事了。对于闭包,在外函数outer中 最后return inner,咱们在调用外函数 demo = outer() 的时候,outer返回了inner,inner是一个函数的引用,这个引用被存入了demo中。因此接下来咱们再进行demo() 的时候,至关于运行了inner函数。

  同时咱们发现,一个函数,若是函数名后紧跟一对括号,至关于如今我就要调用这个函数,若是不跟括号,至关于只是一个函数的名字,里面存了函数所在位置的引用。

2 外函数把临时变量绑定给内函数:

  按照咱们正常的认知,一个函数结束的时候,会把本身的临时变量都释放还给内存,以后变量都不存在了。通常状况下,确实是这样的。可是闭包是一个特别的状况。外部函数发现,本身的临时变量会在未来的内部函数中用到,本身在结束的时候,返回内函数的同时,会把外函数的临时变量送给内函数绑定在一块儿。因此外函数已经结束了,调用内函数的时候仍然可以使用外函数的临时变量。

  在我编写的实例中,我两次调用外部函数outer,分别传入的值是5和7。内部函数只定义了一次,咱们发现调用的时候,内部函数是能识别外函数的临时变量是不同的。python中一切都是对象,虽然函数咱们只定义了一次,可是外函数在运行的时候,其实是按照里面代码执行的,外函数里建立了一个函数,咱们每次调用外函数,它都建立一个内函数,虽然代码同样,可是却建立了不一样的对象,而且把每次传入的临时变量数值绑定给内函数,再把内函数引用返回。虽然内函数代码是同样的,但其实,咱们每次调用外函数,都返回不一样的实例对象的引用,他们的功能是同样的,可是它们实际上不是同一个函数对象。

 

闭包中内函数修改外函数局部变量:

  在闭包内函数中,咱们能够随意使用外函数绑定来的临时变量,可是若是咱们想修改外函数临时变量数值的时候发现出问题了!咋回事捏??!!(哇哇大哭)

  在基本的python语法当中,一个函数能够随意读取全局数据,可是要修改全局数据的时候有两种方法:1 global 声明全局变量 2 全局变量是可变类型数据的时候能够修改

  在闭包内函数也是相似的状况。在内函数中想修改闭包变量(外函数绑定给内函数的局部变量)的时候:

    1 在python3中,能够用nonlocal 关键字声明 一个变量, 表示这个变量不是局部变量空间的变量,须要向上一层变量空间找这个变量。

    2 在python2中,没有nonlocal这个关键字,咱们能够把闭包变量改为可变类型数据进行修改,好比列表。

上代码!!!

复制代码
 1 #修改闭包变量的实例
 2 # outer是外部函数 a和b都是外函数的临时变量
 3 def outer( a ):
 4     b = 10  # a和b都是闭包变量
 5     c = [a] #这里对应修改闭包变量的方法2
 6     # inner是内函数
 7     def inner():
 8         #内函数中想修改闭包变量
 9         # 方法1 nonlocal关键字声明
10         nonlocal  b
11         b+=1
12         # 方法二,把闭包变量修改为可变数据类型 好比列表
13         c[0] += 1
14         print(c[0])
15         print(b)
16     # 外函数的返回值是内函数的引用
17     return inner
18 
19 if __name__ == '__main__':
20 
21     demo = outer(5)
22     demo() # 6  11
复制代码

从上面代码中咱们能看出来,在内函数中,分别对闭包变量进行了修改,打印出来的结果也确实是修改以后的结果。以上两种方法就是内函数修改闭包变量的方法。

 

还有一点须要注意:使用闭包的过程当中,一旦外函数被调用一次返回了内函数的引用,虽然每次调用内函数,是开启一个函数执行事后消亡,可是闭包变量实际上只有一份,每次开启内函数都在使用同一份闭包变量

上代码!

复制代码
 1 #coding:utf8
 2 def outer(x):
 3     def inner(y):
 4         nonlocal x
 5         x+=y
 6         return x
 7     return inner
 8 
 9 
10 a = outer(10)
11 print(a(1)) //11
12 print(a(3)) //14
复制代码

两次分别打印出11和14,因而可知,每次调用inner的时候,使用的闭包变量x其实是同一个。

 

 

 

 

 

闭包有啥用??!!

  不少伙伴很糊涂,闭包有啥用啊??还这么难懂!

   3.1装饰器!!!装饰器是作什么的??其中一个应用就是,咱们工做中写了一个登陆功能,咱们想统计这个功能执行花了多长时间,咱们能够用装饰器装饰这个登陆模块,装饰器帮咱们完成登陆函数执行以前和以后取时间。

   3.2面向对象!!!经历了上面的分析,咱们发现外函数的临时变量送给了内函数。你们回想一下类对象的状况,对象有好多相似的属性和方法,因此咱们建立类,用类建立出来的对象都具备相同的属性方法。闭包也是实现面向对象的方法之一。在python当中虽然咱们不这样用,在其余编程语言入好比avaScript中,常常用闭包来实现面向对象编程

   3.3实现单利模式!! 其实这也是装饰器的应用。单利模式毕竟比较高大,,须要有必定项目经验才能理解单利模式究竟是干啥用的,咱们就不探讨了。

相关文章
相关标签/搜索