字典理解产生看似没有根据的 NameError
Dict comprehension produces seemingly unwarranted NameError
我正在使用 brian2
到 运行 神经网络模拟。为了在每次模拟期间记录数据,我正在创建 brian2
的 SpikeMonitor
class 的几个实例。我想将这些监视器存储在使用字典理解创建的字典中。
作为测试,我在交互式会话中执行以下命令:
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)) for pop in record_pops}
Out[4]: {'mon_pe_mt': <SpikeMonitor, recording spikemonitor>}
一切看起来都很棒。但是现在当我把这段代码移到下面的函数中时
def test_record():
pe_mt = brian2.PoissonGroup(1, 100 * brian2.Hz)
record_pops = ['pe_mt']
return {'mon_' + pop: brian2.SpikeMonitor(eval(pop)) for pop in
record_pops}
并调用它,我得到以下错误
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)) for 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)) for pop in
63 record_pops}
64 # DEBUG ###################
/home/daniel/Science/dopa_net/brian/ardid/tests.py in <module>()
NameError: name 'pe_mt' is not defined
这是怎么回事? 'pe_mt' 是在函数内定义的。
请注意,如果我将字典理解更改为列表理解,如
return [brian2.SpikeMonitor(eval(pop)) for pop in record_pops]
没有报错!我得到了 SpikeMonitor
个对象的列表,这些对象定义得当。
现在已删除的一个答案建议我使用 locals()[pop]
而不是 eval(pop)
。请注意,这会引发等效错误:
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]) for 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]) for pop in
63 record_pops}
64 # DEBUG ###################
KeyError: 'pe_mt'
一:忘记eval
,因为如果传递给它的字符串是表达式或函数调用,而不是标识符,它可能会导致意想不到的事情发生。如果你真的需要通过名称获取局部变量,你可以使用locals()[name]
.
干净地完成它
文档:locals
二:所有推导式和生成器表达式(python2.x中的列表推导式除外)have their own namespace, so locals()
inside the comprehension will refer to that one - the one that doesn't have your variable. Same goes for eval
that captures your local variables by default:
If the locals dictionary is omitted it defaults to the globals dictionary. If both dictionaries are omitted, the expression is executed in the environment where eval() is called.
您可以通过提前获取它们来解决这个问题:
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)) for pop in record_pops}
# or better
return {'mon_' + pop: brian2.SpikeMonitor(groups[pop]) for pop in record_pops}
或者更传统,没有locals
:
def test_record():
groups = {
"pe_mt": brian2.PoissonGroup(1, 100 * brian2.Hz),
}
return {'mon_' + key: brian2.SpikeMonitor(value) for key, value in groups.iteritems()}
不推荐的解决方法:
def test_record():
pe_mt = brian2.PoissonGroup(1, 100 * brian2.Hz)
record_pops = ['pe_mt']
my_loc = locals()
return {'mon_' + pop: brian2.SpikeMonitor(eval(my_loc[pop])) for pop in
record_pops}
或者使用普通循环来构建你的字典:
def test_record():
pe_mt = brian2.PoissonGroup(1, 100 * brian2.Hz)
record_pops = ['pe_mt']
d = {}
for pop in record_pops:
d['mon_' + pop] = brian2.SpikeMonitor(locals()[pop]))
return d
或者简单地使用字典来保存对象:
def test_record():
d = {"pe_mt":brian2.PoissonGroup(1, 100 * brian2.Hz)}
record_pops = ['pe_mt']
return {'mon_' + pop: brian2.SpikeMonitor(d[pop]) for pop in record_pops}
我正在使用 brian2
到 运行 神经网络模拟。为了在每次模拟期间记录数据,我正在创建 brian2
的 SpikeMonitor
class 的几个实例。我想将这些监视器存储在使用字典理解创建的字典中。
作为测试,我在交互式会话中执行以下命令:
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)) for pop in record_pops}
Out[4]: {'mon_pe_mt': <SpikeMonitor, recording spikemonitor>}
一切看起来都很棒。但是现在当我把这段代码移到下面的函数中时
def test_record():
pe_mt = brian2.PoissonGroup(1, 100 * brian2.Hz)
record_pops = ['pe_mt']
return {'mon_' + pop: brian2.SpikeMonitor(eval(pop)) for pop in
record_pops}
并调用它,我得到以下错误
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)) for 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)) for pop in
63 record_pops}
64 # DEBUG ###################
/home/daniel/Science/dopa_net/brian/ardid/tests.py in <module>()
NameError: name 'pe_mt' is not defined
这是怎么回事? 'pe_mt' 是在函数内定义的。
请注意,如果我将字典理解更改为列表理解,如
return [brian2.SpikeMonitor(eval(pop)) for pop in record_pops]
没有报错!我得到了 SpikeMonitor
个对象的列表,这些对象定义得当。
现在已删除的一个答案建议我使用 locals()[pop]
而不是 eval(pop)
。请注意,这会引发等效错误:
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]) for 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]) for pop in
63 record_pops}
64 # DEBUG ###################
KeyError: 'pe_mt'
一:忘记eval
,因为如果传递给它的字符串是表达式或函数调用,而不是标识符,它可能会导致意想不到的事情发生。如果你真的需要通过名称获取局部变量,你可以使用locals()[name]
.
文档:locals
二:所有推导式和生成器表达式(python2.x中的列表推导式除外)have their own namespace, so locals()
inside the comprehension will refer to that one - the one that doesn't have your variable. Same goes for eval
that captures your local variables by default:
If the locals dictionary is omitted it defaults to the globals dictionary. If both dictionaries are omitted, the expression is executed in the environment where eval() is called.
您可以通过提前获取它们来解决这个问题:
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)) for pop in record_pops}
# or better
return {'mon_' + pop: brian2.SpikeMonitor(groups[pop]) for pop in record_pops}
或者更传统,没有locals
:
def test_record():
groups = {
"pe_mt": brian2.PoissonGroup(1, 100 * brian2.Hz),
}
return {'mon_' + key: brian2.SpikeMonitor(value) for key, value in groups.iteritems()}
不推荐的解决方法:
def test_record():
pe_mt = brian2.PoissonGroup(1, 100 * brian2.Hz)
record_pops = ['pe_mt']
my_loc = locals()
return {'mon_' + pop: brian2.SpikeMonitor(eval(my_loc[pop])) for pop in
record_pops}
或者使用普通循环来构建你的字典:
def test_record():
pe_mt = brian2.PoissonGroup(1, 100 * brian2.Hz)
record_pops = ['pe_mt']
d = {}
for pop in record_pops:
d['mon_' + pop] = brian2.SpikeMonitor(locals()[pop]))
return d
或者简单地使用字典来保存对象:
def test_record():
d = {"pe_mt":brian2.PoissonGroup(1, 100 * brian2.Hz)}
record_pops = ['pe_mt']
return {'mon_' + pop: brian2.SpikeMonitor(d[pop]) for pop in record_pops}