Python中的闭包


概念

闭包:在外函数中定义一个内函数,内函数中使用外函数的临时变量,并且外函数的返回值是内函数的引用

正常情况:一个函数结束,函数内部所有的东西都会释放掉还给内存,局部变量都会消失。

闭包是一种特殊的情况,外函数在结束的时候发现自己的临时变量被内函数使用,就会把临时变量绑定给内函数,然后再结束。


闭包的作用

装饰器:比如统计一个模块的耗费时间,就可以写为一个装饰器。该装饰器还可以统计其他模块的耗费时间


闭包函数

def outer(a):
    b = 1

    def inner():
        print(a + b)
    return inner

if __name__ == '__main__':
    demo = outer(2)
    demo()

外函数中a、b都是临时变量,在inner内函数中用到了a、b临时变量,然后外函数返回内函数的引用。
在main中demo == outer(2),外函数的临时变量是a=2、b=1,并创建了内函数,然后将内函数引用返回给demo。
demo()调用内函数,内函数使用了外部函数的临时变量。demo存储了外函数的返回值,demo()执行了内函数。


内函数的引用

引用是什么:在Python中一切都是对象,类、方法、int、float、list。
Python对象的三要素是:

  • id:唯一标示一个对象
  • Type:标示对象的类型
  • Value:对象的值
def fun():
    pass
b = fun
print(id(fun))
print(id(b))
print(fun)
print(b)
print(type(fun))
print(type(b))

输出结果:

4437951080
4437951080
<function fun at 0x10885c268>
<function fun at 0x10885c268>
<class 'function'>
<class 'function'>
[Finished in 0.0s]

b变量和fun方法是一样的,实际上b()和fun()调用的是同一个方法。b是指向fun函数的引用。

所以在调用外函数 demo = outer(2) 的时候,outer返回了inner,inner是内函数的引用,这个引用被存入到了demo中,相当于上面的b指向fun函数。在执行demo()相当于运行了inner函数。


内函数生存状态

def outer(a):
    b = 1

    def inner():
        print(a + b)
    return inner

if __name__ == '__main__':
    demo = outer(2)
    print(id(outer))
    print(id(demo))
    demo=outer((3))
    print(id(outer))
    print(id(demo))

输出结果

4354835048
4355603856
4354835048
4355603584
[Finished in 0.1s]

在上面的实例中,两次调用外部函数outer,外函数的id都是相同,所以是是同一个对象。两次调用内部函数inner,但是内函数的id不相同,所以不是同一个对象。
外函数每次把传入的临时变量值,绑定给内函数,内函数返回引用。每次调用内函数,返回的都是不同的实例对象的引用。


闭包变量的修改

Python变量的修改遵循LEGB法则:Local -> Enclosed -> Global -> Built-in

  • L:Local代表在一个函数或者类方法内部,局部作用域。
  • E:Enclosed可能是嵌套函数,闭包。
  • G:Global就是全局作用域。
  • B:built-in是Python为自身保留的特殊名称。
def outer(a):
    b = 1

    def inner():
        nonlocal b
        b += 1
        print(b)
    return inner
if __name__ == '__main__':
    demo = outer(2)
    demo()

nonlocal:声明一个变量,表示变量不是局部变量,向上一层变量空间寻找。


闭包变量存在时间

闭包变量的存在过程:外函数返回内函数引用,虽然每次调用内函数,是函数执行后死亡,但是闭包变量就一份,每次开始函数使用的是同一份闭包变量。

def outer(a):
    def inner(b):
        nonlocal a
        a += b
        return a
    return inner
if __name__ == '__main__':
    demo = outer(10)
    print(demo(1))
    print(demo(2))

打印11和13,可见每次调用inner的时候,使用的是同一个闭包变量a。
但是传的b参数运行结束的时候,b变量会消亡,使用下一次传入的b变量。传入的参数是临时的,但是inner这个内函数一直没有消失,闭包变量也是跟随inner引用存在的。
inner指向其他对象,这个inner函数才会被垃圾回收

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值