闭包(closure)定义是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)。定义里这个引用环境并不易懂。实际来说,pyhton 中函数是可以嵌套的,如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包。
>>>def addx(x):
>>> def adder(y): return x + y
>>> return adder
>>> c = addx(8)
>>> type(c)
<type 'function'>
>>> c.__name__
'adder'
>>> c(10)
返回函数名而并不立即执行,这里内部函数adder 调用了外部作用域的x。
但是内部函数并不能修改外部作用域的变量:
def foo():
a = 1
def bar():
a = a + 1
return a
return bar
这一段代码会报错,显示bar函数内的a未被定义。
可以再定义同名的变量,但是内部是内部变量,外部是外部变量,并不互相影响。
def foo():
m = 0
def foo1():
m = 1
print(m)
print(m)
foo1()
print(m)
foo()
结果是 0 1 0
解决方案,python3通过nonlocal关键字来解决:
def foo():
m = 0
def foo1():
nonlocal m
m = 1
print(m)
print(m)
foo1()
print(m)
foo()
该语句指定m并不是函数内局部变量。
下面是看到别人使用闭包的例子,还不是甚懂,先粘上来。比如说,如果你希望函数的每次执行结果,都是基于这个函数上次的运行结果。我以一个类似棋盘游戏的例子来说明。假设棋盘大小为50*50,左上角为坐标系原点(0,0),我需要一个函数,接收2个参数,分别为方向(direction),步长(step),该函数控制棋子的运动。棋子运动的新的坐标除了依赖于方向和步长以外,当然还要根据原来所处的坐标点,用闭包就可以保持住这个棋子原来所处的坐标。
origin = [0, 0]
legal_x = [0, 50]
legal_y = [0, 50]
def create(pos=origin):
def player(direction,step):
# 这里应该首先判断参数direction,step的合法性,比如direction不能斜着走,step不能为负等
# 然后还要对新生成的x,y坐标的合法性进行判断处理,这里主要是想介绍闭包,就不详细写了。
new_x = pos[0] + direction[0]*step
new_y = pos[1] + direction[1]*step
pos[0] = new_x
pos[1] = new_y
#注意!此处不能写成 pos = [new_x, new_y],因为参数变量不能被修改,而pos[]是容器类的解决方法
return pos
return player
player = create() # 创建棋子player,起点为原点
print player([1,0],10) # 向x轴正方向移动10步
print player([0,1],20) # 向y轴正方向移动20步
print player([-1,0],10) # 向x轴负方向移动10步