为什么是[6,6,6,6]

为什么是[6,6,6,6]

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

result = [m(2) for m in num()]

print(result)

wait …

先不急往下看,请在脑海里先推测一下这段代码的运行结果,!!看看是否符合自己的常规理解

go on

​ 这段代码的输出结果是[6, 6, 6, 6],而不是预期的[0, 2, 4, 6]。这是因为在 Python 中,函数闭包的特性可能导致这种意外的行为。

什么是闭包

​ 闭包是一种特殊的函数,它具有访问外部函数作用域中变量的能力。这意味着它可以“捕获”外部函数中的变量,并在其生命周期内保持对它们的引用。

让我们看看一个简单的例子:

def outer():
    x = 1
    def inner():
        print(x)
    return inner

my_func = outer()
my_func() # 1

​ 在这个例子中,函数 inner() 是一个闭包,因为它可以访问外部函数 outer() 中的变量 x。我们将 outer() 函数的返回值赋给变量 my_func,然后调用 my_func()。此时,my_func() 调用内部函数 inner(),它可以访问外部变量 x 的值,并将其打印出来。

代码分析

现在,让我们回到原始代码并解释为什么它会输出[6, 6, 6, 6, 6]。

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

result = [m(2) for m in num()]
print(result) 

# [6, 6, 6, 6]

​ 在这段代码中,函数 num() 返回一个列表,其中包含 4 个 lambda 函数。这些 lambda 函数使用变量 i 和参数 x 来计算一个值。在每次迭代中,变量 i 的值都会增加 1,最终达到 3。

然后,代码创建一个新列表 result,其中包含调用这些 lambda 函数的结果。在这里,每个 lambda 函数都调用 i * x,其中 i 是 0 到 3 之间的值。然而,由于 lambda 函数是闭包,它们将引用外部作用域中的变量 i。因此,当 m(2) 被调用时,每个 lambda 函数都将引用最终的值 3。

因此,对于每个 lambda 函数,调用 m(2) 将返回 3 * 2 的值 6。这就是为什么结果列表包含四个 6 的原因。

如何避免这个问题

​ 如果嵌套函数引用了上层作用域中的一个变量,改变量被循环改变,循环结束后,该变量的值,为最后一次循环完成时被引用变量的值。

​ 如果想要让这类代码能够工作,那么需要使用默认参数把当前的值传递给嵌套作用域的变量。而不是在 lambda 函数内部引用它们。

例如:

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

result = [m(2) for m in num()]
print(result) 

# [0, 2, 4, 6]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值