我正在寻找一种优雅的方法,使用一些嵌套的dicts和列表(即javascript样式的对象语法)在dict上使用属性访问来获取数据 .
例如:
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
应该可以通过这种方式访问:
>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar
我认为,如果没有递归,这是不可能的,但是什么是获得dicts的对象样式的好方法?
30 回答
有一个名为namedtuple的集合助手,可以为你做到这一点:
Update: 在Python 2.6及更高版本中,考虑namedtuple数据结构是否适合您的需求:
替代方案(原始答案内容)是:
然后,您可以使用:
令人惊讶的是没有人提到Bunch . 这个库专门用于提供对dict对象的属性样式访问,并且完全符合OP的要求 . 示范:
一个Python 3库可以在https://github.com/Infinidat/munch获得 - Credit to codyzu
然后添加递归到这个,你就完成了 .
edit 这就是我实现它的方式:
我认为这是前面例子中最好的方面,这就是我想出的:
可以与任何深度的任何序列/字典/值结构一起使用 .
如果您的dict来自
json.loads()
,您可以在一行中将其转换为对象(而不是dict):另见How to convert JSON data into a Python object .
如果你想要将dict键作为一个对象(或者作为一个困难键的dict)来访问,那么递归执行它,并且还能够更新原始dict,你可以这样做:
用法示例:
我最终尝试了AttrDict和Bunch库,发现它们对我的使用来说太慢了 . 在我和朋友调查之后,我们发现编写这些库的主要方法导致库通过嵌套对象进行主动递归,并在整个过程中复制字典对象 . 考虑到这一点,我们做了两个关键的改变 . 1)我们使属性延迟加载2)而不是创建字典对象的副本,我们创建轻量级代理对象的副本 . 这是最终的实施 . 使用此代码的性能提升令人难以置信 . 当使用AttrDict或Bunch时,这两个库分别占用了我的请求时间的1/2和1/3(什么!?) . 这段代码将时间缩短到几乎为零(在0.5ms的范围内) . 这当然取决于您的需求,但如果您在代码中使用此功能,请务必使用这样的简单方法 .
请参阅https://stackoverflow.com/users/704327/michael-merickel的原始实现here .
另外需要注意的是,这个实现非常简单,并没有实现您可能需要的所有方法 . 您需要在DictProxy或ListProxy对象上根据需要编写它们 .
x.__dict__.update(d)
应该没问题 .这应该让你开始:
它不需要将列表包装在UserList中并重载
__getitem__
以包装dicts .旧的问答,但我得到更多的话题 . 似乎没有人谈论递归字典 . 这是我的代码:
您可以使用 custom object hook 来利用标准库的 json module :
用法示例:
并且 not strictly read-only 与
namedtuple
一样,即你可以改变值 - 而不是结构:我偶然发现了我需要以递归方式将一个dicts列表转换为对象列表的情况,所以根据Roberto的片段在这里为我做了什么工作:
请注意,出于显而易见的原因,任何元组都将转换为其等效列表 .
希望这可以帮助别人,就像你的所有答案一样,对我来说,伙计们 .
想上传我的这个小范例的版本 .
它保留了导入到类中的类型的属性 . 我唯一关心的是从字典中覆盖你解析的方法 . 但除此之外看似坚实!
将
dict
分配给空对象的__dict__
怎么样?当然,除非你递归地遍历dict,否则你的嵌套dict示例会失败:
你的示例列表元素可能是
Mapping
,这是(键,值)对的列表,如下所示:我知道这里已经有很多答案了,我迟到了,但是这个方法会递归并且“就地”将字典转换为类似对象的结构...在3.x.x中工作
这是实现SilentGhost原始建议的另一种方法:
让我解释一下我前一段时间使用过的解决方案 . 但首先,我没有的原因通过以下代码说明:
给出了这个错误:
因为“from”是一个Python关键字,所以你不能使用某些字典键允许 .
现在我的解决方案允许直接使用他们的名字访问字典项 . 但它也允许你使用“字典语义” . 以下是带有示例用法的代码:
这是另一个实现:
[编辑]错过了关于在列表中处理dicts的一点,而不仅仅是其他的dicts . 添加了修复 .
这个怎么样:
然后可以这样使用:
我认为dict由数字,字符串和dict组成,大部分时间都足够了 . 所以我忽略了元组,列表和其他类型没有出现在dict的最终维度中的情况 .
考虑到继承,结合递归,它方便地解决了打印问题,并提供了两种查询数据的方法,一种是编辑数据的方法 .
请参阅下面的示例,该描述描述了有关学生的一些信息:
结果:
这也很有效
用法:
Build 我对“python: How to add property to a class dynamically?”的回答:
您在要转换的字典上调用
makedata
,或者根据您期望的输入调用trydata
,它会吐出一个数据对象 .笔记:
如果需要更多功能,可以将elif添加到
trydata
.显然,如果你想要
x.a = {}
或类似的话,这将不起作用 .如果需要只读版本,请使用the original answer中的类数据 .
我有一些问题
__getattr__
没有被调用所以我构建了一个新的样式类版本:此版本还添加了
NoneStruct
,在调用未设置的属性时返回 . 这允许None测试以查看属性是否存在 . 当确切的dict输入未知时(设置等)非常有用 .我的字典是这种格式:
可以看出,我有 nested dictionaries 和 list of dicts . 这是因为addr_bk是从使用lwpb.codec转换为python dict的协议缓冲区数据解码的 . 存在可选字段(例如,电子邮件=>其中密钥可能不可用)和重复字段(例如,电话=>转换为字典列表) .
我尝试了以上提出的所有解决方案 . 有些不能很好地处理嵌套字典 . 其他人无法轻松打印对象细节 .
只有Dawie Strauss的解决方案dict2obj(dict)效果最好 .
当无法找到密钥时,我已经增强了一点处理:
然后,我测试了它: