例如:
>>> 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
我认为,如果没有递归,这是不可能实现的,但有没有一种好的方法可以获取字典的对象样式?
>>> 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
我认为,如果没有递归,这是不可能实现的,但有没有一种好的方法可以获取字典的对象样式?
更新:在Python 2.6及以上版本中,考虑是否需要使用namedtuple
数据结构来满足您的需求:
>>> from collections import namedtuple
>>> MyStruct = namedtuple('MyStruct', 'a b d')
>>> s = MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s
MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s.a
1
>>> s.b
{'c': 2}
>>> s.c
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyStruct' object has no attribute 'c'
>>> s.d
['hi']
class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)
然后,您可以使用:
>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2
def __repr__(self):
return '<%s>' % str('\n '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.items()))
- six8argparse.Namespace
中(它也定义了 __eq__
,__ne__
,__contains__
)。 - wim令人惊讶的是,没有人提到Bunch。这个库专门为字典对象提供属性风格的访问,并且正好符合OP的要求。以下是一个演示:
>>> from bunch import bunchify
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = bunchify(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
>>> from munch import DefaultMunch
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> obj = DefaultMunch.fromDict(d)
>>> obj.b.c
2
>>> obj.a
1
>>> obj.d[1].foo
'bar'
class obj(object):
def __init__(self, d):
for k, v in d.items():
if isinstance(k, (list, tuple)):
setattr(self, k, [obj(x) if isinstance(x, dict) else x for x in v])
else:
setattr(self, k, obj(v) if isinstance(v, dict) else v)
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = obj(d)
>>> x.b.c
2
>>> x.d[1].foo
'bar'
obj
类继承自argparse.Namespace
以获得额外的功能,例如可读性更好的字符串表示。 - Serranoif isinstance(k, (list, tuple)):
:k是键,你应该测试v! - ishahakx = type('new_dict', (object,), d)
然后将递归添加到其中,你就完成了。
编辑 这是我实现它的方式:
>>> d
{'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> def obj_dic(d):
top = type('new', (object,), d)
seqs = tuple, list, set, frozenset
for i, j in d.items():
if isinstance(j, dict):
setattr(top, i, obj_dic(j))
elif isinstance(j, seqs):
setattr(top, i,
type(j)(obj_dic(sj) if isinstance(sj, dict) else sj for sj in j))
else:
setattr(top, i, j)
return top
>>> x = obj_dic(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
top_instance = top()
并在返回 top
的地方返回它呢? - pancakex
和 x.b
这样的“树枝”,它们返回丑陋的 <class '__main__.new'>
。 - MarkHu# Applies to Python-3 Standard Library
class Struct(object):
def __init__(self, data):
for name, value in data.items():
setattr(self, name, self._wrap(value))
def _wrap(self, value):
if isinstance(value, (tuple, list, set, frozenset)):
return type(value)([self._wrap(v) for v in value])
else:
return Struct(value) if isinstance(value, dict) else value
# Applies to Python-2 Standard Library
class Struct(object):
def __init__(self, data):
for name, value in data.iteritems():
setattr(self, name, self._wrap(value))
def _wrap(self, value):
if isinstance(value, (tuple, list, set, frozenset)):
return type(value)([self._wrap(v) for v in value])
else:
return Struct(value) if isinstance(value, dict) else value
可用于任何深度的序列、字典或值结构。
def __repr__(self): return '{%s}' % str(', '.join("'%s': %s" % (k, repr(v)) for (k, v) in self.__dict__.iteritems()))
- MarkHudef __repr__(self): return ("{ " + str(", ".join([f"'{k}': {v}" for k, v in [(k, repr(v)) for (k, v) in self.__dict__.items()]])) + " }")
- Sebastian有一个叫做namedtuple
的集合助手可以帮助您完成这个任务:
from collections import namedtuple
d_named = namedtuple('Struct', d.keys())(*d.values())
In [7]: d_named
Out[7]: Struct(a=1, b={'c': 2}, d=['hi', {'foo': 'bar'}])
In [8]: d_named.a
Out[8]: 1
d_named = namedtuple('Struct', d)(**d)
。 - xiaobingjson.loads()
,您可以通过一行代码将其转换为对象而不是字典:import json
from collections import namedtuple
json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
请参见 如何将JSON数据转换为Python对象。
.loads
慢得多。 - michaelsnowden你可以利用标准库的json
模块和自定义对象钩子:
import json
class obj(object):
def __init__(self, dict_):
self.__dict__.update(dict_)
def dict2obj(d):
return json.loads(json.dumps(d), object_hook=obj)
示例用法:
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> o = dict2obj(d)
>>> o.a
1
>>> o.b.c
2
>>> o.d[0]
u'hi'
>>> o.d[1].foo
u'bar'
它与namedtuple
不同,不是严格只读的,也就是说,您可以更改值 - 而不是结构:
>>> o.b.c = 3
>>> o.b.c
3
json.JSONEncoder
和 object_hook
进行扩展,因此它相当通用。 - Sandro综合之前例子中我认为最好的方面,这是我想出来的:
class Struct:
"""The recursive class for building and representing objects with."""
def __init__(self, obj):
for k, v in obj.items():
if isinstance(v, dict):
setattr(self, k, Struct(v))
else:
setattr(self, k, v)
def __getitem__(self, val):
return self.__dict__[val]
def __repr__(self):
return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.items()))
def __init__(self, dct):
for k, v in dct.iteritems():
setattr(self, k, isinstance(v, dict) and self.__class__(v) or v)
这也省略了对Struct
的显式调用。 - George V. Reillyisinstance(v, dict)
的检查最好改为isinstance(v, collections.Mapping)
,这样它就可以处理未来类似字典的事物。 - hobs我最终尝试了AttrDict和Bunch两个库,但发现它们对我的使用来说速度太慢了。我的一个朋友和我深入研究后发现,这些库的主要方法会强制递归遍历嵌套对象,并在整个过程中创建字典对象的副本。因此,在此基础上我们进行了两个关键改变:1)我们将属性设为惰性加载,2)我们不再创建字典对象的副本,而是创建轻量级代理对象的副本。这是最终的实现代码。使用这段代码时,性能提升非常显著。当使用AttrDict或Bunch这两个库时,它们分别占用了我的请求时间的一半和三分之一(什么!?)。 而这段代码几乎没有消耗任何时间(大约在0.5毫秒范围内)。当然,这取决于您的需求,但如果您的代码中需要频繁使用这种功能,一定要选择像这样简单的东西。
class DictProxy(object):
def __init__(self, obj):
self.obj = obj
def __getitem__(self, key):
return wrap(self.obj[key])
def __getattr__(self, key):
try:
return wrap(getattr(self.obj, key))
except AttributeError:
try:
return self[key]
except KeyError:
raise AttributeError(key)
# you probably also want to proxy important list properties along like
# items(), iteritems() and __len__
class ListProxy(object):
def __init__(self, obj):
self.obj = obj
def __getitem__(self, key):
return wrap(self.obj[key])
# you probably also want to proxy important list properties along like
# __iter__ and __len__
def wrap(value):
if isinstance(value, dict):
return DictProxy(value)
if isinstance(value, (tuple, list)):
return ListProxy(value)
return value
请参阅 此处 的原始实现,作者为 https://stackoverflow.com/users/704327/michael-merickel。
另外需要注意的是,这个实现相当简单,并没有实现您可能需要的所有方法。您需要根据DictProxy或ListProxy对象的要求编写这些方法。
collections.abc
中的 Mapping
和 Sequence
,而不是 collections
。 - hlongmore
from_
而不是_from
。 - Kosgetattr(x, 'from')
来代替重命名属性。 - George V. Reillyd1.b.c
),我认为很明显你应该使用来自库的某些东西,例如collections中的namedtuple,就像这个答案所建议的一样,... - Andy Hayden