Как использовать exec для назначения списка переменной в соответствии со словарем в Python3? - PullRequest
0 голосов
/ 11 октября 2018

Я хочу присвоить список переменной, в то время как list и variable оба хранятся в словаре measurements.Это версия Python 2 measurements с меньшим количеством переменных:

measurements = {'tg': [8.184e+16, 8.345e+16, 8.045e+16, 8.520e+16, 8.322e+16, 7.622e+16, 4.305e+16, 2.203e+16]}

def f():
    for key,val in measurements.items():
        exec(key + ' = val') in globals(),locals()
    print (tg)
f()

Однако, как уже упоминалось в другой вопрос , он не подходит для Python 3. Если я пишу код какэто:

measurements = {'tg': [8.184e+16, 8.345e+16, 8.045e+16, 8.520e+16, 8.322e+16, 7.622e+16, 4.305e+16,
 2.203e+16]}

def f():
    for key,val in measurements.items():
        ldict = {}
        exec(key + ' = val', globals(),ldict)
        key = ldict[key]
        # exec(key + ' = val') in globals(),locals()
    print (tg)
f()

Я получил эту ошибку: NameError: name 'val' is not defined

Ответы [ 2 ]

0 голосов
/ 11 октября 2018
measurements = {'tg': [8.184e+16, 8.345e+16, 8.045e+16, 8.520e+16, 8.322e+16, 7.622e+16, 4.305e+16, 2.203e+16]}

def f():
    for key,val in measurements.items():
        exec('{} = {}'.format(key, val))
    print (tg)

    local = locals()
    for key in measurements.keys():
        print 'Key: ', key, ', Value: ', local[key]
f()

python3:

measurements = {'tg': [8.184e+16, 8.345e+16, 8.045e+16, 8.520e+16, 8.322e+16, 7.622e+16, 4.305e+16, 2.203e+16]}

def f():
    for key,val in measurements.items():
        exec('global {};{} = {}'.format(key, key, val))
    print ('tg: ', tg)

    vars = globals()
    for key in measurements.keys():
        print ('Key: ', key, ', Value: ', vars[key])
f()

вывод:

[8.184e+16, 8.345e+16, 8.045e+16, 8.52e+16, 8.322e+16, 7.622e+16, 4.305e+16, 2.203e+16]
Key:  tg , Value:  [8.184e+16, 8.345e+16, 8.045e+16, 8.52e+16, 8.322e+16, 7.622e+16, 4.305e+16, 2.203e+16]
0 голосов
/ 11 октября 2018

Трюк ldict = {} создает замещающее локальное пространство имен для использования внутри exec.Это полезно, потому что dict, возвращаемый locals(), не записывает ваши фактические локальные данные, как это было в Python 2.

Но это замещающее пространство имен {} пусто.Он не содержит locals(), поэтому в нем нет val.Попробуйте вместо этого использовать ldict = {**locals()}, чтобы скопировать содержимое ваших местных жителей в замещающие местные ldict.


Помните, что вы должны прочитать все "локальные", созданные exec из ldict.Таким образом, print(tg) также не будет работать, потому что он был назначен только в одном из замещающих локальных пространств имен.Вы, вероятно, не хотите делать новый каждый цикл.Просто .update() тот, который вы делаете заранее.

def f():
    ldict = {}
    for key,val in measurements.items():
        ldict.update(locals())
        exec(key + ' = val', globals(),ldict)
        key = ldict[key]
        # exec(key + ' = val') in globals(),locals()
    print (ldict['tg'])

Число и имена локальных элементов должны быть заранее известны компилятору в Python3 для оптимизации производительности.(Это не относится к globals(), они все еще пишут.)

Если вы знаете их заранее, вы можете просто назначить их, например,

tg = ldict['tg']
print(tg)

Если вам нужноболее чем один вы можете распаковать словарь в локальные, как

a, b, c = (ldict[key] for key in ['a', 'b', 'c'])

или вы можете сбросить весь диктовку в простое пространство имен и получить к ним доступ с помощью . вместо [].

from types import SimpleNamespace

# ...

ns = SimpleNamespace(**ldict)
print(ns.tg)

Вы также можете просто exec любой код, для которого нужны новые локальные объекты, поскольку вы можете дать exec ldict пространство имен.

exec("print(tg)", globals(), ldcit)

Я понимаю, что ваш пример кодаможет быть упрощено от оригинала, но, похоже, не нужно exec вообще.Обычно считается плохим тоном использовать exec, если он вам абсолютно не нужен, так как это приводит к путанице в инструментах статического анализа и медленной компиляции строк во время выполнения, особенно если повторяется в таком цикле.

Если вы должны использоватьexec, лучше поместить цикл в строку exec (используйте тройные кавычки), чем вызов exec внутри цикла.Таким образом, строка должна быть скомпилирована только один раз, а не для каждого цикла.

...