1

Я использую brian2 для запуска нейронных сетевых симуляций. Чтобы записывать данные во время каждого моделирования, я создаю несколько экземпляров класса brian2SpikeMonitor. Я хочу хранить эти мониторы в dict, созданный с использованием понимания dict.Dict comprehension производит кажущееся необоснованным NameError

В качестве теста я выполнить следующее в интерактивном режиме:

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' -, определенный в функции.

Обратите внимание, что если изменить Dict понимание в списке понимание, как в

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' 
+0

что 'Eval (поп)' должны делать? –

+0

здесь, 'pop = 'pe_mt'.'' eval (pop) 'дает мне объект' pe_mt', 'SpikeMonitor'. – dbliss

+0

Почему бы просто не сохранить объект? –

ответ

0

One: Забудьте eval, потому что это может привести к неожиданным вещам произойти, если строка, переданная ему это выражение или вызов функции, а не идентификатор. Если вам действительно необходимо получить локальную переменную по имени, вы можете сделать это с использованием locals()[name].

Docs: locals


Два: Все постижения и выражение генератора (кроме списковых в Python 2.x) have their own namespace, так locals() внутри понимание будет относиться к этому один - тот, который не делает есть переменная.То же самое относится и к eval что 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()} 
+0

можете ли вы сделать аргумент в пользу превосходства 'locals() [name]' относительно 'eval'? – dbliss

+0

Он будет вести себя предсказуемо, если «имя» окажется чем-то иным, чем идентификатором. Кроме того, здесь вам все равно нужно построить 'locals' заранее, поэтому вызов' eval' для получения значения из этого словаря является супер-круговым – Kos

0

А, не рекомендованную обходной путь:

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} 

Или использовать обычный цикл, чтобы построить свой Dict:

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 

Или просто использовать Dict для хранения объектов:

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} 
+0

, почему не рекомендуется? – dbliss

+0

Потому что это может помешать компилятору оптимизировать ваш код. –

+0

что бы вы посоветовали? и как насчет этого кода исключает оптимизацию? – dbliss