闭包
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。它只不过是个“内层”的函数,由一个名字(变量)来指
代,而这个名字(变量)对于“外层”包含它的函数而言,是本地变量。
看一个例子:
#!/usr/bin/python def squ(): fs = [] for i in range(1, 4): # range(1, 4) = [1, 2, 3] def f(): return i*i fs.append(f) return fs f1, f2, f3 = squ() # same as f1 = squ()[0] print f1() print f2() print f3()
执行这个函数,你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果是:
9 9 9
这是为什么呢?
首先明确,调用squ()后,squ()中存放的是三个f函数,而不是f函数计算出来的结果。
闭包 = 函数 + 引用环境,也就是说,当形成一个闭包之后,放进闭包的并不是具体的值。在上面的例子中,闭包中应该只包含变量i的地址,告诉程序当他被调用时这个i应该从哪里找,此时并不涉及i的值。只有当真正调用时,才根据此时i的值算出最终结果,而此时在返回3个函数之后,i的值已经成为3了,所以当我们开始调用函数时,返回的值就都是9了。
换一种写法理解起来应该容易
#!/usr/bin/python def squ(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fs print squ()[0]()
这样执行打出的结果将是:
9
当调用squ函数的时候,squ()这个list中存储的值是三个f函数,这三个f函数指向同一个变量i的地址。所以结果是一样的。
那么如何用第一个函数返回1, 4, 9呢? 只需要在squ函数被调用的时候,list中存储的f函数指向的参数值不同就行了,例如下面的写法:
#!/usr/bin/python def squ(): fs = [] for i in range(1, 4): def f(j=i): return j*j # if return i*i, answer will be 9 fs.append(f) return fs f1, f2, f3 = squ() print f1() print f2() print f3()
f函数的值不再与i变化,而是记录下当前i的值用自己的参数j表示。