如何将dict中的所有键作为局部变量加载,这是一种更好的方法?

时间:2011-01-10 19:26:39

标签: python

给这本词典:

>>> options = {'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3'}}}

最好的方法是什么?:

>>> foo(options)
>>> print DATABASES
{'default': {'ENGINE': 'django.db.backends.sqlite3'}}

我解决这个问题是本地人()。更新(选项),但我在想,如果有更好的解决方案。

4 个答案:

答案 0 :(得分:7)

import inspect

allowed_vars = set(["min_", "max_", "path", ...])
def update_globals(dic):
    caller_frame = inspect.currentframe(1)
    globals = caller_frame.f_globals
    # here, you _could_ simply do globals.update(dic) 
    # but it is  evil
    for key, value in dic.items():
        #here you should carefully verify each key, and value for not
        #not dangerous pairs, with stuff like:
        #if key not in allowed_vars:
        #    sys.stderr.write("Warning: invalid variable in configuration update\n")
        #     continue
        #if type(value) not in (string, int, float):
        #    #(issue error)
        #    continue
        globals[key] = value

示例:

>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> update_globals({"a": 5})
>>> a
5

更新2016-06 几个星期前,我将extradict Python软件包放在一起 - 它可以在pypi now上找到。它的一个特性是MapGetter上下文管理器,它可以准确地提供所要求的内容 做一些事情:

from extradict import MapGetter

def myfunc():
    options = {'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3'}}}
    with MapGetter(options) as options:
         from options import DATABASES
 ...

和其他正常的“from .... import ....”用法,但来自字典或映射对象(包括默认字典)。

答案 1 :(得分:3)

正如goldmab所说,修改函数内的locals()输出将不起作用:

SyntaxError: invalid syntax
>>> def foo():
...     locals().update({'a': 1})
...     print a
... 
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in foo
NameError: global name 'a' is not defined

这也不是一个非常干净的方式,但它可以完成这项工作:

>>> def foo():
...     options = {'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3'}}}
...     for k, v in options.items():
...         exec('%s = v' % k)
...     print DATABASES
... 
>>> foo()
{'default': {'ENGINE': 'django.db.backends.sqlite3'}}

顺便说一句,请注意,你的dict中的每个键都需要作为变量。因此,例如,如果字典包含“DATABASE-USERNAME”作为键,尝试将其分配给变量将导致异常。此外,如果从不值得信任的来源获取选项字典,这样做会使您容易受到代码注入攻击。 (关键可以说是“import os; os.system('sudo adduser scriptkiddie'); ...”

答案 2 :(得分:3)

我认为你想要的只是:

globals().update(**options)

答案 3 :(得分:0)

您无法在运行时修改函数本地,因为局部变量名称列表是已编译函数对象的静态部分。

>>> def a(): b = 5
... 
>>> a.func_code.co_varnames
('b',)

这仅适用于全局范围,因为locals()globals()相同,全局变量存储在字典中,这是动态的(与函数本地不同)。

>>> locals() is globals()
True

看起来你正在从另一个源更新Django设置模块中的值。我不会说这一定是坏事,但为了清楚起见,您应该使用globals()代替locals()