I've got the following dictionary:
d = {
'A': {
'param': {
'1': {
'req': True,
},
'2': {
'req': True,
},
},
},
'B': {
'param': {
'3': {
'req': True,
},
'4': {
'req': False,
},
},
},
}
I want to have a generator which will give me for each first level keys, the required parameters.
req = {}
for key in d:
req[key] = (p for p in d[key]['param'] if d[key]['param'][p].get('req', False))
So here, for each key in d, I get parameter p only if req is True.
However, when I try to use my generator, it raises a KeyError exception:
>>> 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'
The generator expressions you assign to req[key] binds on the key variable. But key changes from 'A' to 'B' in the loop. When you iterate over the first generator expression, it will evaluate key to 'B' in its if condition, even though key was 'A' when you created it.
The conventional way to bind to a variable's value and not its reference, is to wrap the expression in a lambda with a default value, and then call it immediately.
for key in d:
req[key] = (lambda key=key: (p for p in d[key]['param'] if d[key]['param'][p].get('req', False)))()
Result:
1
2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With