python中闭包示例

概念上的东西这里就不详细解释了,为什么需要闭包(Closures)呢?个人理解就是某些情况下你需要在外部访问函数内部的变量时,闭包就该大显身手了。闭包的一种典型表现就是函数内部定义了新的函数。这里举几个例子以记录使用闭包时的几个注意点,例子来源于这里,大神用javascript写的示例,这里改成python的,也顺便说说遇到的坑。

例子1:闭包中局部变量是引用而非拷贝

def say667():
    '''闭包中局部变量是引用而非拷贝'''
    num = 666
    def saynum():
        print "in saynum:", num
    num += 1
    return saynum
temp = say667()
temp()

输出结果是667,有C、C++基础的应该不难理解这个吧?

例子2:多个函数绑定同一个闭包,因为他们定义在同一个函数内。

def setupSomeGlobals():
    '''多个函数绑定同一个闭包,因为他们定义在同一个函数内。'''
    num = [666]
    def get_num():
        print "num:", num
    def add_num():
        num[0] += 1
    def set_num(x):
        num[0] = x
    global getnum
    getnum = get_num
    global addnum
    addnum = add_num
    global setnum
    setnum = set_num
setupSomeGlobals()
getnum()
addnum()
getnum()
setnum(10)
getnum()

注意这个例子中使用py2有坑,见这里。如果你定义一个比如整型这种不可变类型,则在py2中报错“UnboundLocalError: local variable ’num’ referenced before assignment”。解决办法就是定义列表、字典甚至类,在py3中使用nonlocal关键字。

例子3:当在一个循环中赋值函数时,这些函数将绑定同样的闭包

def buildlist(mylist):
    '''当在一个循环中赋值函数时,这些函数将绑定同样的闭包,可以理解为上一个例子的变体'''
    result = []
    for one in mylist:
        item = "item:%s" % one
        result.append(lambda :(item,one))
    return result
def testlist():
    fnlist = buildlist([1,2,3])
    for i in fnlist:
        print i()
testlist()

这个例子中python和javascript的返回结果不同,因为python的for循环结束时就是值就是最后一个,而不会再+1。

例子4:外部函数所有局部变量都在闭包内,即使这个变量声明在内部函数定义之后。

def sayAlice():
    '''外部函数所有局部变量都在闭包内,即使这个变量声明在内部函数定义之后。'''
    def say():
        print "hello,",name
    name = "Alice"
    return say
helloAlice = sayAlice()
helloAlice()

这个我以前还真没注意到……

例子5:每次函数调用的时候创建一个新的闭包

def newClosure(someNum,someRef):
    '''每次函数调用的时候创建一个新的闭包'''
    num = [someNum] #注意这里,理由同示例2
    arr = [1,2,3]
    ref = someRef
    def fun(x):
        num[0] += x
        arr.append(x)
        print "num:",num,"arr:",arr,"ref:",ref
    return fun
closure1=newClosure(40,{'someVar':'closure 1'});
closure2=newClosure(1000,{'someVar':'closure 2'});
closure1(5)
closure2(-10)

至于应用,我第一个想到的就是python中各种装饰器了。