为什么在这个生成器中会出现KeyError错误?

4

我有以下字典:

d = {
    'A': {
        'param': {
            '1': {
                'req': True,
            },
            '2': {
                'req': True,
            },
        },
    },
    'B': {
        'param': {
            '3': {
                'req': True,
            },
            '4': {
                'req': False,
            },
        },
    },
}

我希望有一个生成器,可以为每个一级键提供所需的参数。
req = {}
for key in d:
    req[key] = (p for p in d[key]['param'] if d[key]['param'][p].get('req', False))

因此,在d中的每个键上,当reqTrue时,我只获取参数p

然而,当我尝试使用我的生成器时,它会引发KeyError异常:

>>> req
{'A': <generator object <genexpr> at 0x27b8960>,
 'B': <generator object <genexpr> at 0x27b8910>}
>>> for elem in req['A']:
...     print elem
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-6-a96226f95cce> in <module>()
----> 1 for elem in req['A']:
      2     print elem
      3 

<ipython-input-4-1732088ccbdb> in <genexpr>((p,))
      1 for key in d:
----> 2         req[key] = (p for p in d[key]['param'] if d[key]['param'][p].get('req', False))
      3 

KeyError: '1'
2个回答

4
你赋给req[key]的生成器表达式绑定在变量key上。但是,在循环中,key从'A'变为'B'。当你遍历第一个生成器表达式时,它将在其if条件中评估key为'B',即使在创建它时key是'A'。
绑定到变量值而不是其引用的传统方法是将表达式包装在具有默认值的lambda中,并立即调用它。
for key in d:
    req[key] = (lambda key=key: (p for p in d[key]['param'] if d[key]['param'][p].get('req', False)))()

结果:

1
2

3
这是因为在生成器执行时,使用的是key最新值。
假设for key in d:按顺序遍历键'A', 'B',第一次生成器应该使用key = 'A',但由于闭包问题,它使用了以'B'为键的项。而这没有'1'子条目。
更糟糕的是,生成器中的key变量有两个不同的值:用于for p in d[key]['param']部分的是“正确”的值,而用于if d[key]['param'][p].get('req', False)的是“闭包值”,即最后一个值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接