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()}