如何在python3中使用exec根据字典将列表分配给变量?

时间:2018-10-11 03:19:57

标签: python python-3.x python-2.7 exec local-variables

我想为变量分配列表,而listvariable都存储在字典measurements中。这是measurements的Python 2版本,变量较少:

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

但是,如another question中所述,它不适用于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

3 个答案:

答案 0 :(得分:1)

ldict = {}技巧创建了一个替代的本地命名空间,供在exec内部使用。这很有用,因为locals()返回的字典不会像Python 2中那样直接写入您的实际本地语言。

但是替代名称空间{}为空。它不包含您的locals(),因此其中没有val。尝试使用ldict = {**locals()}代替将您的本地人的内容复制到替代本地人ldict


请记住,您必须从exec读取exec创建的所有“本地”。因此,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调用。这样一来,字符串只需要编译一次,而不必为每个循环编译一次。

答案 1 :(得分:1)

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]

答案 2 :(得分:0)

几年后,但我意识到您可以(ab)使用在类声明中创建的临时名称空间来获取函数内部的write-through locals()名称空间。这使您可以直接翻译Python 2版本:

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():
    class _:
        for key,val in measurements.items():
            exec(key + ' = val', globals(), locals())
        print (tg)

f()