Python闭包的概念

首先了解一下:如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数。

闭包概念:

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。实际上闭包可以看做一种更加广义的函数概念。因为其已经不再是传统意义上定义的函数。
一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。

闭包语法:

#常规函数语法:
#计算两个数值的求和
def func ():
	a = 1
	b = 2
	return a + b

#常规函数调用
num1 = func()
print(num1)
print(type(num1))

以上命令执行结果如下:

3
(class,'int')
#闭包函数语法:
#计算两个数值的差值
# sum是外函数,add是内部函数
def sum(a):
	def add(b):
		return a - b    # 在内函数中,用到了这个外函数的临时变量a
	return add

#闭包函数调用
# 在这里我们调用外函数传入参数1,此时外函数临时变量 a是1
# 并创建了内函数,内函数传入参数2 b是2,然后把内函数的引用返回存给了 num2
# 外函数结束的时候发现内部函数将会用到自己的临时变量a,这个临时变量就不会释放,会绑定给这个内部函数
# 我们调用内部函数,看一看内部函数是不是能使用外部函数的临时变量
# num3存了外函数的返回值,也就是add函数的引用,这里相当于执行add函数
num2 = sum(1)
num3 = num2(2)
#返回值为1 - 2 = -1
print(num3)
#还有一点需要注意:使用闭包的过程中,一旦外函数被调用一次返回了内函数的引用,
#虽然每次调用内函数,是开启一个函数执行过后消亡,
#但是闭包变量实际上只有一份,每次开启内函数都在使用同一份闭包变量
#两次分别打印出-1和-11,由此可见,每次调用add的时候,使用的闭包变量a实际上是同一个。
num4 = num2(12)
print(num4)
#根据函数类型分析
print(type(num2))
print(type(num3))
#num2为function类型,num3为int类型

以上命令执行结果如下:

-1
-11
(class,'function')
(class,'int')

闭包延伸:

从上面例子是我写的一个最简单的很典型的闭包。

1 外函数返回了内函数的引用:
  引用是什么?在python中一切都是对象,包括整型数据1,函数,其实是对象。
  当我们进行a=1的时候,实际上在内存当中有一个地方存了值1,然后用a这个变量名存了1所在内存位置的引用。
  引用就好像c语言里的指针,大家可以把引用理解成地址。a只不过是一个变量名字,a里面存的是1这个数值所在的地址,就是a里面存了数值1的引用。
  相同的道理,当我们在python中定义一个函数def num2(): 的时候,内存当中会开辟一些空间,存下这个函数的代码、内部的局部变量等等。
  这个num2只不过是一个变量名字,它里面存了这个函数所在位置的引用而已。
  我们还可以进行x = num2, y = num2, 这样的操作就相当于,把num2里存的东西赋值给x和y,这样x 和y 都指向了num2函数所在的引用,在这之后我们可以用x() 或者 y() 来调用我们自己创建的num2() ,调用的实际上根本就是一个函数,x、y和num2三个变量名存了同一个函数的引用。
  有了上面的解释,我们可以继续说,返回内函数的引用是怎么回事了。对于闭包,在外函数sum中 最后return add,我们在调用外函数 num2 = sum() 的时候,sum返回了add,add是一个函数的引用,这个引用被存入了num2中。所以接下来我们再进行num2() 的时候,相当于运行了add函数。
  同时我们发现,一个函数,如果函数名后紧跟一对括号,相当于现在我就要调用这个函数,如果不跟括号,相当于只是一个函数的名字,里面存了函数所在位置的引用。

2 外函数把临时变量绑定给内函数:
  按照我们正常的认知,一个函数结束的时候,会把自己的临时变量都释放还给内存,之后变量都不存在了。一般情况下,确实是这样的。但是闭包是一个特别的情况。外部函数发现,自己的临时变量会在将来的内部函数中用到,自己在结束的时候,返回内函数的同时,会把外函数的临时变量送给内函数绑定在一起。所以外函数已经结束了,调用内函数的时候仍然能够使用外函数的临时变量。
  在执行中,内部函数是能识别外函数的临时变量是不一样的。python中一切都是对象,虽然函数我们只定义了一次,但是外函数在运行的时候,实际上是按照里面代码执行的,外函数里创建了一个函数,我们每次调用外函数,它都创建一个内函数,虽然代码一样,但是却创建了不同的对象,并且把每次传入的临时变量数值绑定给内函数,再把内函数引用返回。虽然内函数代码是一样的,但其实,我们每次调用外函数,都返回不同的实例对象的引用,他们的功能是一样的,但是它们实际上不是同一个函数对象。

闭包的作用:

 
  1.装饰器!!!装饰器是做什么的??其中一个应用就是,我们工作中写了一个登录功能,我们想统计这个功能执行花了多长时间,我们可以用装饰器装饰这个登录模块,装饰器帮我们完成登录函数执行之前和之后取时间。
  2.面向对象!!!经历了上面的分析,我们发现外函数的临时变量送给了内函数。大家回想一下类对象的情况,对象有好多类似的属性和方法,所以我们创建类,用类创建出来的对象都具有相同的属性方法。闭包也是实现面向对象的方法之一。在python当中虽然我们不这样用,在其他编程语言入比如avaScript中,经常用闭包来实现面向对象编程
  3.实现单利模式!! 其实这也是装饰器的应用。单利模式毕竟比较高大,需要有一定项目经验才能理解单利模式到底是干啥用的,我们就不探讨了。

实例1:

#编写基础版计数器,外函数counter,内函数add_one
def counter():
	cnt = [0]
	def add_one():
		cnt[0] += 1
		return cnt[0]
	return add_one

num1 = counter()

print(num1())
print(num1())
print(num1())

以上命令执行结果如下:

1
2
3

实例2:

#编写复杂版计数器,外函数counter,内函数add_one
def counter(FIRST=0):
	cnt =[FIRST]
	def add_one():
		cnt[0] += 1
		return cnt[0]
	return add_one

num5 = counter(5)
num10 = counter(10)

print(num5())
print(num5())
print(num5())
print(num10())
print(num10())
print(num10())

以上命令执行结果如下:

6
7
8
11
12
13
发布了26 篇原创文章 · 获赞 2 · 访问量 537

猜你喜欢

转载自blog.csdn.net/weixin_42741880/article/details/104693360