【问题标题】:Dictionary comprehension with lambda functions gives wrong results使用 lambda 函数的字典理解给出错误的结果
【发布时间】:2016-04-23 00:09:09
【问题描述】:

我在 Python 3.5.1 中尝试了以下代码:

>>> f = {x: (lambda y: x) for x in range(10)}
>>> f[5](3)
9

很明显这应该返回5。我不明白其他价值从何而来,我也找不到任何东西。

似乎它与引用有关 - 它总是返回 f[9] 的答案,这是分配的最后一个函数。

这里有什么错误,应该怎么做才能正常工作?

【问题讨论】:

    标签: python dictionary lambda


    【解决方案1】:

    Python 作用域是词法。闭包将引用变量的名称和范围,而不是变量的实际对象/值。

    发生的情况是每个 lambda 都在捕获变量 x 而不是 x 的值。

    在循环结束时,变量 x 被绑定到 9,因此 每个 lambda 都会引用这个值为 9 的 x

    为什么@ChrisP 的回答有效:

    make_func 强制评估 x 的值(因为它被传递 成一个函数)。因此,lambda 当前的值为 x 我们避免了上述范围问题。

    def make_func(x):
        return lambda y: x
    
    f = {x: make_func(x) for x in range(10)}
    

    【讨论】:

    • 另一种简写是f = {x: (lambda y, x=x: x) for x in range(10)},因为函数默认参数是在定义时绑定的,所以它们会绑定x,而不是姓名 x.
    • 这听起来像是一个非常愚蠢的问题(我对 lambda 不太熟悉),但是 make_func(x) 是如何工作的呢?我可以想象 f[5](3) 的意思是 -> f = {5:make_func(5)}。那么make_func(5)(3)怎么等于5呢?
    • 字典理解将整数的字典键变成函数的值。 f[5] 返回以 5 为键的字典中的值,该值恰好是函数 lambda y: x。请注意,lambda 忽略传入 (y) 的任何内容并始终返回 x。这就是 lambda 将返回 5 或 9 的原因(由于上述问题)。
    • @gnicholas 我明白了,所以基本上 lambda 依赖于全局 x 值(即字典范围内的全局?)
    • 关于“词法作用域”的评论让我感到困惑。许多其他语言具有词法范围(例如,Haskell、Java),并且不受此约束。例如(哈斯克尔):import Data.Maplet f = fromList [(x, \y -> x) | x <- [1..10]]; fmap ($ 3) (Data.Map.lookup 5 f) 导致 Just 5。你能澄清一下你是如何使用“词法范围”这个词的吗?
    【解决方案2】:

    以下应该有效:

    def make_func(x):
        return lambda y: x
    
    f = {x: make_func(x) for x in range(10)}
    

    您代码中的x 最终引用了最后一个x 值,即9,但在我的代码中,它引用了函数范围内的x

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-12
      • 1970-01-01
      • 1970-01-01
      • 2015-03-22
      • 1970-01-01
      • 2014-04-07
      相关资源
      最近更新 更多