Python的闭包与延时绑定问题

转载于:https://blog.youkuaiyun.com/yitiaodashu/article/details/79025502

今天一个在自学python的同学问了这么一个问题,感觉挺典型的,于是整理如下:

def mul():
    return [lambda x : i*x for i in range(4)]

print([m(2) for m in mul()])

# output:
# [6, 6, 6, 6]

为毛结果是 [6, 6, 6, 6] 而不是我们以为的 [0, 2, 4, 6] 呢?

要理解这道题,我们得先弄清楚什么是闭包。

闭包定义: 
1、闭包是一个嵌套函数 
2、闭包必须返回嵌套函数 
3、嵌套函数必须引用一个外部的非全局的局部自由变量

这不是闭包:

def foo1():
    print('嘿嘿')
    def foo2():
        print('哈哈')
foo2()

这才是闭包:

def foo1(n):
    def foo2(m):
        return n + m
    return foo2

a = foo1(2)
print(a(3))

先是传foo2给foo1,传递的是函数,之后再把3传递给函数foo2,返回计算的结果。

这也是闭包:

def foo1():
    var = 'hello'
    def foo2():
        print(var)
    return foo2
a = foo1()
a()

回到题首,这是一个闭包,为了便于理解,我们可以把代码改成:

def mul():
    func_list = []
    for i in range(4):
        def lam(x):
            return x*i
        func_list.append(lam)
    return func_list

print([m(2) for m in mul()])

怎么理解呢?简单来说,在python里,相对而言的局部变量绑定的是值,非局部变量绑定的是空间, 而不是值本身,所以,for循环生成的i,相对于函数lam来说,是全局变量,所以绑定的是i所在的内存地址,但i最后变成了3,lam绑定的是3。

所以导致了,生成的四个函数所得值时相同的.

那么如何实现结果为 [0, 2, 4, 6] 呢? 按照刚才的思路,我们只需将lam函数中的 i 变成局部变量,这样函数lam绑定的就是值, 而不是内存地址:

def mul():
    func_list = []
    for i in range(4):
        def lam(x,i=i):
            return x*i
        func_list.append(lam)
    return func_list

print([m(2) for m in mul()])

这时候lam函数返回的 i 就是函数本身的参数 i 指定默认值,即是外部的 i,如果感觉比较绕的话,我们可以把参数换一下:

def mul():
    func_list = []
    for i in range(4):
        def lam(x,n=i):
            return x*n
        func_list.append(lam)
    return func_list

print([m(2) for m in mul()])

这时候因为 n 是局部变量,所以绑定的是 n 的值,这样应该能理解了吧!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值