一 .定义
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).这个定义是相对直白的,
闭包有三个条件:
1.函数嵌套
2,内部函数调用外部函数的变量
3.返回内部函数
def a(a): def B(b): s = a + b return s return B cd =a(6) ss = cd(4) print(ss)#结果为10
二 闭包中注意的事项
闭包中是不能修改外部作用域的局部变量的值
1 def foo(): 2 m = 0 3 def foo1(): 4 m = 1 5 print(m) 6 print(m) 7 foo1() 8 print(m) 9 foo()
###########################
0
1
0
以下这段代码是在python中使用闭包时一段经典的错误代码
这段程序的本意是要通过在每次调用闭包函数时都对变量a进行递增的操作。但在实际使用时
def foo(): a = 1 def bar(): a = a + 1 return a return bar
这是因为在执行代码 c = foo()时,python会导入全部的闭包函数体bar()来分析其的局部变量,python规则指定所有在赋值语句左面的变量都是局部变量,则在闭包bar()中,变量a在赋值符号"="的左面,被python认为是bar()中的局部变量。再接下来执行print c()时,程序运行至a = a + 1时,因为先前已经把a归为bar()中的局部变量,所以python会在bar()中去找在赋值语句右面的a的值,结果找不到,就会报错。解决的方法很简单,使用语句nonloacal a就可以了,该语句显式的指定a不是闭包的局部变量。
方法一
def foo(): a = [1] def bar(): a[0] = a[0] + 1 return a[0] return bar
方法二
def foo(): a = 1 def bar(): nonlocal a a = a + 1 return a return bar c = foo() print(c())
经典错误问题:
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。这是因为当把函数加入flist列表里时,python还没有给i赋值,只有当执行时,再去找i的值是什么,这时在第一个for循环结束以后,i的值是2,所以以上代码的执行结果是4,4,4.解决方法也很简单,改写一下函数的定义就可以了。
for i in range(3): def foo(x,y=i): print x + y flist.append(foo)
三 闭包的用途
1 .当闭包执行完后,仍然能够保持住当前的运行环境。
2.闭包可以根据外部作用域的局部变量来得到不同的结果,这有点像一种类似配置功能的作用,我们可以修改外部的变量,闭包根据这个变量展现出不同的功能。
1 def make_filter(keep): 2 def the_filter(file_name): 3 file = open(file_name) 4 lines = file.readlines() 5 file.close() 6 filter_doc = [i for i in lines if keep in i] 7 return filter_doc 8 return the_filter
如果我们需要取得文件"result.txt"中含有"pass"关键字的行,则可以这样使用例子程序
filter = make_filter("pass") filter_result = filter("result.txt")