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导入上测试的,因此核心类型非常简单)
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__
\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