Python:将dict中的变量加载到命名空间中

Python:将dict中的变量加载到命名空间中,python,variables,scope,locals,Python,Variables,Scope,Locals,我想使用函数中定义的一组局部变量,在函数之外。因此,我在返回值中传递x=locals() 我如何将该字典中定义的所有变量加载到函数外部的名称空间中,以便不使用x['variable']访问值,而只使用variable考虑Bunch备选方案: class Bunch(object): def __init__(self, adict): self.__dict__.update(adict) 因此,如果您有一个字典d,并且希望使用语法x.foo而不是笨拙的d['foo']来访问(读取

我想使用函数中定义的一组局部变量,在函数之外。因此,我在返回值中传递
x=locals()


我如何将该字典中定义的所有变量加载到函数外部的名称空间中,以便不使用
x['variable']
访问值,而只使用
variable
考虑
Bunch
备选方案:

class Bunch(object):
  def __init__(self, adict):
    self.__dict__.update(adict)
因此,如果您有一个字典
d
,并且希望使用语法
x.foo
而不是笨拙的
d['foo']
来访问(读取)它的值,只需执行以下操作即可

x = Bunch(d)
这在函数内部和外部都起作用,而且比将
d
注入
globals()
更干净、更安全!还记得Python禅宗中的最后一行吗

>>> import this
The Zen of Python, by Tim Peters
   ...
Namespaces are one honking great idea -- let's do more of those!

这对于在中导入变量是完全有效的 一个局部空间转换为另一个局部空间,只要 一个人知道他/她在做什么。 我已经多次看到这样的代码以有用的方式被使用。 只是需要小心,不要污染共同的全球空间

您可以执行以下操作:

adict = { 'x' : 'I am x', 'y' : ' I am y' }
locals().update(adict)
blah(x)
blah(y)

将变量导入本地名称空间是一个有效的问题,通常在模板框架中使用

从函数返回所有局部变量:

return locals()
然后按如下方式导入:

r = fce()
for key in r.keys():
   exec(key + " = r['" + key + "']")

总有这样的选择,我不知道这是最好的方法,但它确实有效。假设类型(x)=dict


您可以使用
argparse.Namespace
,而不是创建自己的对象:

from argparse import Namespace
ns = Namespace(**mydict)
要执行相反的操作:

mydict = vars(ns)
使用以下代码段(PY2)从my dict(yaml)配置生成递归命名空间:

串答案是可以的,但缺乏递归和适当的
\uuuu repr\uuuuu
\uuuu eq\uuuu
内置,以模拟您已经可以使用dict执行的操作。此外,递归的关键不仅是在dict上递归,还包括在列表上递归,以便列表中的dict也被转换

我希望这两个选项能够满足您的需要(您可能需要调整
\uu elt()
中的类型检查,以获得更复杂的对象;这些检查主要是在json导入上测试的,因此核心类型非常简单)

  • Bunch方法(根据前面的答案)-对象接受dict并递归地转换它
    repr(obj)
    将返回可以重新解释为等效对象的
    Bunch({…})
  • 类束(对象):
    定义初始(自身,adict):
    “”“从dict递归创建命名空间对象”“”
    self.\u dict.update({k:self.\u elt(v)表示k,v在adict.items()中)
    定义英语教学(自我,英语教学):
    “”“递归到elt以创建叶名称空间对象”“”
    如果类型(elt)为dict:
    返回类型(自身)(elt)
    如果在(列表,元组)中键入(elt):
    返回[self.\u elt(i)for i in elt]
    返回英语教学
    定义报告(自我):
    “返回报告(自我)。”
    返回“%s(%s)”%(键入(self)。\u名称\u,报告(self.\u命令)
    定义(自身、其他):
    返回self.\uu dict.\uuu==其他.\uu dict__
    
  • SimpleNamespace方法-由于已经实现了
    \uuu repr\uuuuuuuu
    \uuuuuu eq\uuuuuu
    ,因此您只需实现递归的
    \uuuu init\uuuuu
    方法:
  • 导入类型
    类RecursiveNamespace(类型.SimpleNamespace):
    #def uu init uu(self,/,**kwargs):#更好,但是Python 3.8+
    定义初始(自我,**kwargs):
    “”“以递归方式创建SimpleNamespace”“”
    self.\u dict.\u.update({k:self.\u elt(v)代表k,v在kwargs.items()中)
    定义英语教学(自我,英语教学):
    “”“递归到elt以创建叶名称空间对象”“”
    如果类型(elt)为dict:
    返回类型(自身)(**elt)
    如果在(列表,元组)中键入(elt):
    返回[self.\u elt(i)for i in elt]
    返回英语教学
    
    RecursiveNamespace类接受关键字参数,这些参数当然可以来自取消引用的dict(例如
    **mydict


    现在让我们来测试一下:

    adict={'foo':'bar','baz':[{'aaa':'bbb','ccc':'ddd'}]
    a=束(adict)
    b=递归命名空间(**adict)
    打印('a:',str(a))
    打印('b:',str(b))
    打印('a==b:',str(a==b))
    
    结果是:

    a: Bunch({'foo': 'bar', 'baz': [Bunch({'aaa': 'bbb', 'ccc': 'ddd'})]})
    b: RecursiveNamespace(baz=[RecursiveNamespace(aaa='bbb', ccc='ddd')], foo='bar')
    a == b : True
    
    虽然它们是不同的类,但因为它们都已初始化为等效的名称空间,并且它们的
    \uuuuuuuuuuuu eq\uuuuuu
    方法仅比较名称空间(
    self.\uuuuuuuuuu dict\uuuuuu
    ),比较两个名称空间对象返回
    True


    您可能还注意到,我使用
    type(self)(…)
    而不是使用类名进行递归-这有两个优点:第一,可以重命名类而不必更新递归调用,第二,如果类是子类,我们将使用子类名进行递归。这也是
    \uuuu repr\uuuu
    类型(self)。\uuuu name\uuuu
    )中使用的名称。

    听起来像是一个糟糕的想法。没有“从模块导入*”的概念那么糟糕,因为您可能对dict中的内容有更多的了解。@johnlaroy为什么这是一个糟糕的想法?但这看起来很优雅:
    globals().update(locals())
    !(我开玩笑,我开玩笑)我在简单的绘图脚本中使用globals().update(locals()),当我以交互方式加载模块或以一次性方式从命令行运行时,我有一些简单的区别。我想我可以把if name=='main':放在文件的顶部,然后就没有函数了。。。但这似乎也同样无伤大雅。无论如何,如果有更好的方法将值从函数内部传递到外部模块,我会感兴趣。我喜欢这个,但它不是递归的。有嵌套字典的解决方案吗?@CleverGuy只要你不使用
    update
    ,你就可以递归地编写它:相反,用
    adict.items()和
    来获得
    k,v
    对,如果类型(v)是dict:self.\uu dict\uk]=Bunch(v)
    ,然后用
    else:self.\uu dict\uk]=v
    。您可以像nam一样访问结果
    class NameSpace(object):
        def __setattr__(self, key, value):
            raise AttributeError('Please don\'t modify config dict')
    
    
    def dump_to_namespace(ns, d):
        for k, v in d.iteritems():
            if isinstance(v, dict):
                leaf_ns = NameSpace()
                ns.__dict__[k] = leaf_ns
                dump_to_namespace(leaf_ns, v)
            else:
                ns.__dict__[k] = v
    
    config = NameSpace()
    dump_to_namespace(config, config_dict)
    
    a: Bunch({'foo': 'bar', 'baz': [Bunch({'aaa': 'bbb', 'ccc': 'ddd'})]})
    b: RecursiveNamespace(baz=[RecursiveNamespace(aaa='bbb', ccc='ddd')], foo='bar')
    a == b : True