Трюк 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 внутри цикла.Таким образом, строка должна быть скомпилирована только один раз, а не для каждого цикла.