【问题标题】:Weird behaviour in python with dict of lambda functionspython中带有lambda函数的奇怪行为
【发布时间】:2016-01-01 08:43:17
【问题描述】:

我已经编写了一个用于生成 lambda 常量函数字典的函数(它是更复杂函数的一部分,但我已将其简化为以下代码):

def function(a):
    _interpolators = {}
    for key in a.keys():
        _interpolators[key] = lambda t: a[key]

    def _interpolate(t):
        return {key:f(t) for (key,f) in _interpolators.items()}
    return _interpolate

if __name__ == '__main__':    
    d = {"foo": 2, "bar":4}
    f = function(d)
    print(f(0)["bar"])

在 OSX El Capitan 上使用 Python 3.5.1,程序的输出是随机的。它可以是24,而我希望只有4。我不太明白这种行为。

请注意,python 2.7.10 似乎没有出现“错误”,当我多次运行该程序时,我总是得到4

这是 python 3.5.1 中的某种错误还是我错过了一些明显的东西?

【问题讨论】:

    标签: python python-3.x lambda


    【解决方案1】:

    关键是在您的lambda 函数中,您已将其定义如下:

    lambda t: a[key]
    

    您没有使用变量t 并尝试通过将变量key 作为字典的键来获取a 的值。并且在下一次您尝试在字典理解中使用此函数时:

    {key:f(t) for (key,f) in _interpolators.items()}
    

    每次你尝试获取f(t),因为t 的存在在这里是多余的,python 尝试通过将变量key 传递给它来获取a 的值,它什么都没有与t 相关。

    最重要的一点是,您希望 python 覆盖 key 变量,因为您在字典理解中使用了 key

    并且由于lamda对象是python中的一个函数并且有自己的本地命名空间,每次它试图返回a[key]它不能访问迭代变量key在理解内所以由于LEGB方式之后它 (lambda) 在 Local 命名空间中查找 key 然后 Enclosure 并没有找到任何东西,它在 Global 范围内查找它。

    并且由于全局 key 是以下部分中的最后一个迭代变量:

    for key in a.keys():
            _interpolators[key] = lambda t: a[key]
    

    lambda 函数会将其用作key。由于在 python 3.X 中dict.keys() 的顺序是随机的,所以结果也是随机的。虽然在 python 2 中不是这样。

    为了解决这个问题,您只需将您的lambda 更改如下:

    lambda t: a[t]
    

    在你的代码中:

    def function(a):
        _interpolators = {}
        for key in a.keys():
            _interpolators[key] = lambda t: a[t]
    
        def _interpolate():
            return {k:f(k) for k,f in _interpolators.items()}
        return _interpolate
    
    if __name__ == '__main__': 
        d = {"foo": 2, "bar":4}
        f = function(d)
        print(f()["bar"])
    

    【讨论】:

    • @NicolasRougier 欢迎,所以您可以通过接受答案告诉社区。​​span>
    • 你的函数做了一些别的事情,而不是 OP 的意图。您的 _interpolators 字典没有任何意义。看看我的解决方案,看看如何正确地做到这一点。
    • @Daniel 这不是 OP 的意图,这只是 OP 试图解释主要问题的一个例子,我在回答中所说的是对 OP 面临的问题的完整描述,并且最后一个建议是针对这个目标的。
    • @Daniel 实际上,我并不关心我通过投票获得并接受的这个假想点,问题是最完整的答案应该被 OP 接受。那是因为未来的读者更关心被接受的答案。
    • @Kasramvd:OP 有一些功能f[key](t)。这显然不是f(k)。解释可能尽可能好,如果它不能解决问题,它就毫无价值。 OP 的 lambda 中的 t 在他的简单示例中可能未使用,但在他的实际问题中未使用。
    【解决方案2】:

    lambda 中的key 取自函数function 的范围。所以它具有a.keys() 中最后一个元素的值。由于安全原因,字典中键的顺序是任意的,每次运行都会在 Python 3 中更改。 将key 设为 lambda 的局部变量:

    def function(a):
        _interpolators = {key: (lambda t, k=key: a[k]) for key in a}
    
        def _interpolate(t):
            return {key:f(t) for (key,f) in _interpolators.items()}
        return _interpolate
    

    【讨论】:

    • @NicolasRougier:FWIW,你可以在hash function in Python 3.3 returns different results between sessions阅读更多关于这个哈希随机化的信息
    • @Kasramvd:Daniel 在前两句话中解释了 OP 代码的主要问题。但是,由于随机的PYTHONHASHSEED 问题,OP 的错误代码的结果因运行而异。
    • @PM2Ring 实际上,如果我要说得更好,这并不能解释主要问题,物品顺序是最后也是最少的问题。都是关于函数命名空间的。
    猜你喜欢
    • 2023-01-26
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多