python - Dict comprehension produces seemingly unwarranted NameError -


i'm using brian2 run neural-network simulations. in order record data during each simulation, i'm creating several instantiations of brian2's spikemonitor class. want store these monitors in dict, created using dict comprehension.

as test, execute following in interactive session:

in [1]: import brian2  in [2]: pe_mt = brian2.poissongroup(1, 100 * brian2.hz)  in [3]: record_pops = ['pe_mt']  in [4]: {'mon_' + pop: brian2.spikemonitor(eval(pop)) pop in record_pops} out[4]: {'mon_pe_mt': <spikemonitor, recording spikemonitor>} 

everything looks great. when move code following function

def test_record():     pe_mt = brian2.poissongroup(1, 100 * brian2.hz)     record_pops = ['pe_mt']     return {'mon_' + pop: brian2.spikemonitor(eval(pop)) pop in             record_pops} 

and call it, following error

in [9]: tests.test_record() --------------------------------------------------------------------------- nameerror                                 traceback (most recent call last) <ipython-input-9-4d3d585b2c97> in <module>() ----> 1 tests.test_record()  /home/daniel/science/dopa_net/brian/ardid/tests.py in test_record()      61     record_pops = ['pe_mt']      62     return {'mon_' + pop: brian2.spikemonitor(eval(pop)) pop in ---> 63                 record_pops}      64     # debug ###################      65     #monitors = utils.record(['pe_mt'], 'spikes', none, none, pe_mt, none, none)  /home/daniel/science/dopa_net/brian/ardid/tests.py in <dictcomp>((pop,))      60     # debug ###################      61     record_pops = ['pe_mt'] ---> 62     return {'mon_' + pop: brian2.spikemonitor(eval(pop)) pop in      63                 record_pops}      64     # debug ###################  /home/daniel/science/dopa_net/brian/ardid/tests.py in <module>()  nameerror: name 'pe_mt' not defined 

what's going on here? 'pe_mt' is defined within function.

note if change dict comprehension list comprehension, in

return [brian2.spikemonitor(eval(pop)) pop in record_pops] 

no error raised! list of spikemonitor objects, defined appropriately.

an answer has been erased suggested use locals()[pop] instead of eval(pop). note raises equivalent error:

in [20]: tests.test_record() --------------------------------------------------------------------------- keyerror                                  traceback (most recent call last) <ipython-input-20-4d3d585b2c97> in <module>() ----> 1 tests.test_record()  /home/daniel/science/dopa_net/brian/ardid/tests.py in test_record()      61     record_pops = ['pe_mt']      62     return {'mon_' + pop: brian2.spikemonitor(locals()[pop]) pop in ---> 63                 record_pops}      64     # debug ###################      65     #monitors = utils.record(['pe_mt'], 'spikes', none, none, pe_mt, none, none)  /home/daniel/science/dopa_net/brian/ardid/tests.py in <dictcomp>((pop,))      60     # debug ###################      61     record_pops = ['pe_mt'] ---> 62     return {'mon_' + pop: brian2.spikemonitor(locals()[pop]) pop in      63                 record_pops}      64     # debug ###################  keyerror: 'pe_mt' 

one: forget eval, because can cause unexpected things happen if string passed expression or function call, rather identifier. if really need local variable name can cleanly using locals()[name].

docs: locals


two: comprehensions , generator expressions (except list comprehensions in python 2.x) have own namespace, locals() inside comprehension refer 1 - 1 doesn't have variable. same goes eval captures local variables default:

if locals dictionary omitted defaults globals dictionary. if both dictionaries omitted, expression executed in environment eval() called.

you can work around getting them earlier:

def test_record():     pe_mt = brian2.poissongroup(1, 100 * brian2.hz)     record_pops = ['pe_mt']     groups = locals()         return {'mon_' + pop: brian2.spikemonitor(eval(pop, globals(), groups)) pop in record_pops}     # or better     return {'mon_' + pop: brian2.spikemonitor(groups[pop]) pop in record_pops} 

or more conventionally, without locals:

def test_record():     groups = {         "pe_mt": brian2.poissongroup(1, 100 * brian2.hz),     }     return {'mon_' + key: brian2.spikemonitor(value) key, value in groups.iteritems()} 

Popular posts from this blog