先看一个闭包的用法:
# -*- coding:utf-8 -*-
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
print count() #实质就是 fs 列表的内容
print f1()
print f2()
print f3()
结果是:
9
9
9
这说明返回的函数并没有立刻执行,而是直到调用了f()才执行,而此时它们所引用的变量i已经变成了3,因此最终结果为9。
试着改进:
# -*- coding:utf-8 -*-
def count():
fs = []
for i in range(1, 4):
def f(i):
return i*i
fs.append(f(i))
return fs
f1, f2, f3 = count()
print f1,f2,f3
#测试一下python的赋值机制
print '\n'
a,b,c=[1,2,3]
print a
print b
print c
#结论:分别赋值,依次对应
上面的代码其实和下面的是没有区别的,
要特别注意函数有括号时和没有括号时的区别(把第一段代码和下面的代码比较)
# -*- coding:utf-8 -*-
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f())
return fs
f1, f2, f3 = count()
print count
print count()
print f1,f2,f3
虽然能得到我们想要的结果,但上面一段代码并没有用到闭包,和 fs.append(i*i) 没有区别。 返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
正确的闭包用法应该如下:
def count():
fs = []
for i in range(1, 4):
def f(j): #1
def g(): #2
return j*j
return g # g函数实质上是f函数的一个闭包
fs.append(f(i)) #i会作为参数,先传递给#1,作为 j 传递给g函数#2,对于每一个i来说,都被g函数锁定了.fs =【f(1),f(2),f(3)】
return fs
f1,f2,f3=count()
print f1
print f1()
print f2()
print f3()
特别值得注意的是,g函数实质上是f函数的一个闭包。每次调用f()时,才具体计算g函数,而print f1时,实际上得到的是函数g——内层函数的返回值 闭包就是把函数作为返回值,具体实现就是函数的嵌套,在这里是 f 函数套 g 函数
内层函数调用外层函数的参数(j)和局部变量,并实现具体的运算,返回值作为内层函数的返回值
外层函数 f 的【返回值】就是内层函数 g ,而非具体的运算结果
要想用外层函数得到具体的返回值,就得调用外层函数
如 f1(),f2(),f3()
函数作为返回值的例子:
# -*- coding:utf-8 -*-
#所谓的函数作为返回值,具体实现就是函数的嵌套,#1套#2
#内层函数调用外层函数的参数(args)和局部变量,并实现具体的运算,返回值作为内层函数的返回值 #3
#外层函数的【返回值】就是内层函数 #4,而非具体的运算结果 #3,可参考#5。
#要想用外层函数得到具体的返回值,就得调用外层函数 #6
def lazy_sum(*args): #1
def sum(): #2
ax=0
for i in args:
ax = ax + i
return ax #3
return sum #4
f=lazy_sum(1,3,5,7) #让f指向lazy_sum,实际上f即lazy_sum
print f #5
print f.__name__
print f()
print lazy_sum(1,3,5,7) # 等于 print f
#当我们调用lazy_sum时,每次调用都会返回一个不同的函数,即使传入相同的参数
f1=lazy_sum(1,3,5,7)
f2=lazy_sum(1,3,5,7)
print f1==f2 #false