如何将字典中的所有键加载为局部变量,更好的方法是什么?

7 投票
4 回答
3688 浏览
提问于 2025-04-16 09:44

给定这个字典:

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

要怎么才能得到这个呢?:

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

我现在是用 locals().update(options) 来解决这个问题,但我在想,是否还有更好的方法。

4 个回答

3

我觉得你想要的其实就是:

globals().update(**options)
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'}}

顺便提一下,你字典里的每个键都必须是可以作为变量的名字。比如,如果字典里有一个键是'DATABASE-USERNAME',那么试图把它赋值给一个变量就会出错。此外,如果你从不可信的来源获取这个选项字典,这样做会让你面临代码注入攻击的风险。比如,某个键可能会写成“import os ; os.system('sudo adduser scriptkiddie') ; ...”这样。

10
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年6月 几周前,我创建了一个叫做 extradict 的Python包 - 现在可以在 pypi上找到。它的一个功能是 MapGetter 上下文管理器,正好满足了大家的需求,具体做法是这样的:

from extradict import MapGetter

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

还有其他正常的“从....导入....”用法,但这些是从字典或映射对象中导入的(包括默认字典)。

撰写回答