Python之闭包

1.什么是闭包

  • 闭包

内层函数访问外层函数的局部变量并返回内层函数:

def f():
		x = 1
		def g():
			return x+1
		return g

如上:函数g()调用外部函数f()的局部变量x,并返回内部函数g,这样的情况称为闭包,函数F()返回的就是闭包

举例:

def plus(number):

	    #在函数内部再定义一个函数,其实这个里面的函数就被认为是闭包
	    def plus_in(number_in):
	        #这里打印一下number_in变量,以便大家可以更清楚传进来的变量时哪一个
	        print str(number_in) + "\r\n"
	        return number+number_in
	    #其实这里返回的就是闭包的结果
	    return plus_in

	#给plus函数赋值,这个20就是给参数number
	v1=plus(20)
	
	#v1是一个函数
	print v1

	#注意这里的100其实给参数number_in
	print v1(100)

以上代码段的输出结果为:

100

	function plus_in at 0x00003890
	
	120

闭包=函数块+定义函数时的环境,注意python中的函数只有在执行时才会在函数体重查找变量的值

1.1 函数:

函数可以作为另一个函数的参数或返回值,可以赋给一个变量。函数可 以嵌套定义,即在一个函数内部可以定义另一个函数

1.2 定义时应用的环境:

函数式语言中,当内嵌函数体内引用到体外的变量时,将会把定义时涉及到的引用环境和函数体打包成一个整体(闭包)返回

2.闭包的作用

3.闭包中的注意事项

3.1 闭包中是不能修改外部作用域的局部变量的

如下:

def outerFun():
	    x = 0 #局部变量
	    def innerFun():
	        x = 1
	        print 'inner x:',x
	    print 'outer x before call inner:',x
	    innerFun()
	    print 'outer x after call inner:',x

	outerFun()

输出结果如下:

outer x before call inner: 0
	inner x: 1
	outer x after call inner: 0

从结果可以看出,闭包并没有修改外部局部变量x的值,即调用前后还是0

3.2 闭包无法直接访问外部函数的局部变量

如下:

def outerFun():
	    x = 1  # 局部变量
	
	    def innerFun():
	        x *=x
	        print 'inner x:', x

	    print 'outer x before call inner:', x
	    innerFun()
	    print 'outer x after call inner:', x


	outerFun()

结果如下:

UnboundLocalError: local variable 'x' referenced before assignment

变量x为局部变量,报错:局部变量在声明前引用,内部函数不能访问外部的局部变量

原因:python规则指定所有在赋值语句左面的变量都是局部变量,则在闭包innerFun中,x*=x相当于将x变为了闭包中的局部变量,所以在执行outerFun中,到了x*=x语句时,python中会先在闭包中找x的值,结果找不到

  • 解决办法:

A. Python3之前使用如下方式

def outerFun():
	    x = [1] # 局部变量
	
	    def innerFun():
	        x[0] *= x[0]
	        print 'inner x:', x[0]
	
	    print 'outer x before call inner:', x
	    innerFun()
	    print 'outer x after call inner:', x
	
	
	outerFun()

B. Python3之后使用如下方式,即说明闭包中的x不是闭包中的局部变量,使用关键字nonlocal

def outerFun():
	    x = 1  # 局部变量
	
	    def innerFun():
	        nonlocal x
			x *=x
	        print 'inner x:', x

	    print 'outer x before call inner:', x
	    innerFun()
	    print 'outer x after call inner:', x


	outerFun()