Python---知识点(闭包延迟绑定)

闭包

在一个函数内部定义另一个函数,外部的函数为外函数,内部的函数为内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这就形成了一个闭包。

通常情况下,一个函数运行结束后,函数内部的所有东西都会被释放掉,局部变量也会消失。但是如果外函数在结束时发现自己的临时变量会在内函数中用到时,就会把这个临时变量绑定给内函数,然后外函数才结束。

有一道很经典的案例:

def multipliers():
  return [lambda x: i * x for i in range(4)]
print ([m(2) for m in multipliers()])

可能我们会认为,上面的函数将输出为[0, 2, 4, 6],但其实输出的是[6, 6, 6, 6],这就是闭包导致的。

闭包函数返回内部函数的引用(即定义的lambda匿名函数),外函数调用结束时会将被内函数引用的局部变量(亦称为闭包变量)绑定至内函数。而延迟绑定指的是,只有在调用内函数时,才会访问闭包变量所指向的对象,不调用时不会访问闭包变量所指向的对象。

上面的例子相当于:

def multipliers():
    funcs = []
    for i in range(4):
        def bar(x):
            return x*i
        funcs.append(bar)
    return funcs
print ([m(2) for m in multipliers()] )

来看下不调用内函数的情况:

def multipliers():
    result = []
    for i in range(4):
        print(i)
        def func(x):
            print("test")
            return i * x
        result.append(func)
    return result
multipliers()

输出为

0
1
2
3

可以从上面的代码看出,未输出test字符,说明我们没有调用内函数,在我们没有调用内函数的同时,循环的 i 变量最后指向了3,当外函数发现自己的临时变量会在内函数中用到时,就把i=3绑定给了内函数,这时外函数已经调用结束。所以当我们调用内函数时,相当于这段伪代码(不能执行的代码):

return [lambda x: 3 * x, lambda x: 3 * x, lambda x: 3 * x, lambda x: 3 * x]

所以输出的结果为[6,6,6,6]

解决方法

将每个循环的 i 值绑定给内函数就行了,也叫做立即绑定

多加个默认参数  i=i

def multipliers():
  return [lambda x,i=i: i * x for i in range(4)]

相当于:

def multipliers():
    funcs = []
    for i in range(4):
        def bar(x, i=i):
            return x * i
        funcs.append(bar)
    return funcs
print ([m(2) for m in multipliers()] )

这样子就把循环过程的每个 i 变量都绑定到内函数了,相当于这段伪代码:

return [lambda x: 0 * x, lambda x: 1 * x, lambda x: 2 * x, lambda x: 3 * x]

 还有一种方法是,采用生成器的方法:函数调用,执行到yield时,就会挂起,等下一次调用时,才会执行yield下面的部分代码(这样就避免一次性执行完for循环):

def multipliers():
  for i in range(4):
      yield lambda x : i * x
print([m(2) for m in multipliers()])

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狼性书生

谢谢鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值