闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)
函数可以作为另一个函数的参数或返回值,可以赋给一个变量。函数可 以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题。如:
def ExFunc(n):
sum=n
def InsFunc():
return sum+1
return InsFunc
myFunc=ExFunc(10)
print (myFunc())
这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)
使用闭包的注意事项
1、闭包中是不能修改外部作用域的局部变量的
def foo():
m = 0
def foo1():
m = 1 // 这是局部变量
print (m)
print (m)
foo1()
print (m)
foo()
结果:0 1 0
2、看一下这个经常犯的错误
def foo():
a = 1
def bar():
a = a + 1
return a
return bar
f = foo()
print(f())
这时候会出现编辑错误,这是因为在执行代码 c = foo()时,python会导入全部的闭包函数体bar()来分析其的局部变量,python规则指定所有在赋值语句左面的变量都是局部变量,则在闭包bar()中,变量a在赋值符号"="的左面,被python认为是bar()中的局部变量。再接下来执行print c()时,程序运行至a = a + 1时,因为先前已经把a归为bar()中的局部变量,所以python会在bar()中去找在赋值语句右面的a的值,结果找不到,就会报错。解决的方法很简单
def foo():
a = [1]
def bar():
a[0] = a[0] + 1
return a[0]
return bar
引用一个对象列表,对象皆为地址,只要用到这里面的东西,会先找到对应的地址
或者这样 nonlocal a 事先声明 a不是局部变量
3,下面看一个函数定义嵌套在循环内,这样的例子经常出现的错误
flist = []
for i in range(3):
def foo(x):
print (x + i)
flist.append(foo)
for f in flist:
f(2)
大家可以觉着结果会是 2,3,4,但实际是4,4,4 个人认为:因为函数嵌套在for循环内部,当没有调用时,函数内根本就没有执行,函数只执行了,def foo(x),但内部的都还没有执行,当调用执行时,再去找外部变量的i时,这时候i已经变成了2,所以 输出的全部是4,4,4
这时可以有人会问,把i的记录下来就行了呗,但是你要怎么记录,我一开始是这样记录的
flist = []
for i in range(3):
def foo(x):
y = i
print (x + y)
flist.append(foo)
for f in flist:
f(2)
大家想想,这样会不会成功呢,可想而知,这样是不能成功的,就如我的想法一样,当函数没有调用时,函数内根本就没有执行,函数只执行了,def foo(x),但内部的都还没有执行,所以当调用时,去外部变量找i,i等于2,把2这个对象赋予y,y还是等于2 ,所以这样是不能成功的,所以我们需要另想办法:可能是我们记录的方式不对吧
因为按照我的想法,函数在调用前只执行了def foo(x),我们可以选择 默认值参数定义函数,把外部变量记录下来如:
flist = []
for i in range(3):
def foo(x,y = i):
print (x + y)
flist.append(foo)
for f in flist:
f(2)
这样的结果是:2,3,4
4、闭包中常见错误
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1,f2,f3 = count()
print("%d %d %d\n" % (f1(),f2(),f3()))
看了这个代码,大家是不是觉着结果是:1,4,9,但它却输出的是 9,9,9 其实和上面的一样,没有记录外部变量的值,下面记录一下:
def count():
fs = []
for i in range(1, 4):
def f(i = i):
return i*i
fs.append(f)
return fs
f1,f2,f3 = count()
print("%d %d %d\n" % (f1(),f2(),f3()))
这时候结果是:1,4,9
也可以这样:
def count():
fs = []
for i in range(1, 4):
def f(i):
def g():
return i*i
return g
fs.append(f(i)) #先直接调用了,把i值记录下来
return fs
f1,f2,f3 = count()
print("%d %d %d\n" % (f1(),f2(),f3()))
闭包的用途:
用途1,当闭包执行完后,仍然能够保持住当前的运行环境。
用途2,闭包可以根据外部作用域的局部变量来得到不同的结果,这有点像一种类似配置功能的作用,我们可以修改外部的变量,闭包根据这个变量展现出不同的功能。比如有时我们需要对某些文件的特殊行进行分析,先要提取出这些特殊行。