Mar*_*arc 509 python dictionary object
我正在寻找一种优雅的方法,使用一些嵌套的dicts和列表(即javascript样式的对象语法)在dict上使用属性访问来获取数据.
例如:
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
Run Code Online (Sandbox Code Playgroud)
应该可以通过这种方式访问:
>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar
Run Code Online (Sandbox Code Playgroud)
我认为,如果没有递归,这是不可能的,但是什么是获得dicts的对象样式的好方法?
Eli*_*sky 638
更新:在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']
Run Code Online (Sandbox Code Playgroud)
替代方案(原始答案内容)是:
class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用:
>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2
Run Code Online (Sandbox Code Playgroud)
Nad*_*mli 103
class obj(object):
def __init__(self, d):
for a, b in d.items():
if isinstance(b, (list, tuple)):
setattr(self, a, [obj(x) if isinstance(x, dict) else x for x in b])
else:
setattr(self, a, obj(b) if isinstance(b, dict) else b)
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = obj(d)
>>> x.b.c
2
>>> x.d[1].foo
'bar'
Run Code Online (Sandbox Code Playgroud)
kon*_*ity 94
令人惊讶的是没有人提到过Bunch.该库专门用于提供对dict对象的属性样式访问,并且完全符合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'
Run Code Online (Sandbox Code Playgroud)
可以在https://github.com/Infinidat/munch上找到一个Python 3库- Credit转到codyzu
Sil*_*ost 60
x = type('new_dict', (object,), d)
Run Code Online (Sandbox Code Playgroud)
然后添加递归到这个,你就完成了.
编辑这是我实现它的方式:
>>> 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'
Run Code Online (Sandbox Code Playgroud)
umb*_*rae 46
有一个名为的集合帮助器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
Run Code Online (Sandbox Code Playgroud)
小智 32
class Struct(object):
"""Comment removed"""
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
Run Code Online (Sandbox Code Playgroud)
可以与任何深度的任何序列/字典/值结构一起使用.
and*_*nee 31
我认为这是前面例子中最好的方面,这就是我想出的:
class Struct:
'''The recursive class for building and representing objects with.'''
def __init__(self, obj):
for k, v in obj.iteritems():
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__.iteritems()))
Run Code Online (Sandbox Code Playgroud)
DS.*_*DS. 28
如果你的dict来自json.loads(),你可以把它变成一个对象(而不是一个dict)在一行:
import json
from collections import namedtuple
json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
Run Code Online (Sandbox Code Playgroud)
另请参见如何将JSON数据转换为Python对象.
Van*_*aro 22
您可以通过自定义对象挂钩来利用标准库的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)
Run Code Online (Sandbox Code Playgroud)
用法示例:
>>> 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'
Run Code Online (Sandbox Code Playgroud)
而且它不是严格只读的,因为它是用namedtuple,即可以改变价值观-不是结构:
>>> o.b.c = 3
>>> o.b.c
3
Run Code Online (Sandbox Code Playgroud)
小智 15
如果你想要将dict键作为一个对象(或者作为一个困难键的dict)访问,那么递归执行它,并且还能够更新原始dict,你可以这样做:
class Dictate(object):
"""Object view of a dict, updating the passed in dict when values are set
or deleted. "Dictate" the contents of a dict...: """
def __init__(self, d):
# since __setattr__ is overridden, self.__dict = d doesn't work
object.__setattr__(self, '_Dictate__dict', d)
# Dictionary-like access / updates
def __getitem__(self, name):
value = self.__dict[name]
if isinstance(value, dict): # recursively view sub-dicts as objects
value = Dictate(value)
return value
def __setitem__(self, name, value):
self.__dict[name] = value
def __delitem__(self, name):
del self.__dict[name]
# Object-like access / updates
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
self[name] = value
def __delattr__(self, name):
del self[name]
def __repr__(self):
return "%s(%r)" % (type(self).__name__, self.__dict)
def __str__(self):
return str(self.__dict)
Run Code Online (Sandbox Code Playgroud)
用法示例:
d = {'a': 'b', 1: 2}
dd = Dictate(d)
assert dd.a == 'b' # Access like an object
assert dd[1] == 2 # Access like a dict
# Updates affect d
dd.c = 'd'
assert d['c'] == 'd'
del dd.a
del dd[1]
# Inner dicts are mapped
dd.e = {}
dd.e.f = 'g'
assert dd['e'].f == 'g'
assert d == {'c': 'd', 'e': {'f': 'g'}}
Run Code Online (Sandbox Code Playgroud)
Ano*_*non 13
>>> def dict2obj(d):
if isinstance(d, list):
d = [dict2obj(x) for x in d]
if not isinstance(d, dict):
return d
class C(object):
pass
o = C()
for k in d:
o.__dict__[k] = dict2obj(d[k])
return o
>>> 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'
Run Code Online (Sandbox Code Playgroud)
Ree*_*erg 13
2021 年,使用 pydantic BaseModel - 将嵌套字典和嵌套 json 对象转换为 python 对象,反之亦然:
https://pydantic-docs.helpmanual.io/usage/models/
>>> class Foo(BaseModel):
... count: int
... size: float = None
...
>>>
>>> class Bar(BaseModel):
... apple = 'x'
... banana = 'y'
...
>>>
>>> class Spam(BaseModel):
... foo: Foo
... bars: List[Bar]
...
>>>
>>> m = Spam(foo={'count': 4}, bars=[{'apple': 'x1'}, {'apple': 'x2'}])
Run Code Online (Sandbox Code Playgroud)
对象字典
>>> print(m.dict())
{'foo': {'count': 4, 'size': None}, 'bars': [{'apple': 'x1', 'banana': 'y'}, {'apple': 'x2', 'banana': 'y'}]}
Run Code Online (Sandbox Code Playgroud)
对象到 JSON
>>> print(m.json())
{"foo": {"count": 4, "size": null}, "bars": [{"apple": "x1", "banana": "y"}, {"apple": "x2", "banana": "y"}]}
Run Code Online (Sandbox Code Playgroud)
字典到对象
>>> spam = Spam.parse_obj({'foo': {'count': 4, 'size': None}, 'bars': [{'apple': 'x1', 'banana': 'y'}, {'apple': 'x2', 'banana': 'y2'}]})
>>> spam
Spam(foo=Foo(count=4, size=None), bars=[Bar(apple='x1', banana='y'), Bar(apple='x2', banana='y2')])
Run Code Online (Sandbox Code Playgroud)
JSON 到对象
>>> spam = Spam.parse_raw('{"foo": {"count": 4, "size": null}, "bars": [{"apple": "x1", "banana": "y"}, {"apple": "x2", "banana": "y"}]}')
>>> spam
Spam(foo=Foo(count=4, size=None), bars=[Bar(apple='x1', banana='y'), Bar(apple='x2', banana='y')])
Run Code Online (Sandbox Code Playgroud)
我最终尝试了AttrDict和束库,并发现它们对我的使用来说太慢了.在我和朋友调查之后,我们发现编写这些库的主要方法导致库通过嵌套对象进行主动递归,并在整个过程中复制字典对象.考虑到这一点,我们做了两个关键的改变.1)我们使属性延迟加载2)而不是创建字典对象的副本,我们创建轻量级代理对象的副本.这是最终的实施.使用此代码的性能提升令人难以置信.当使用AttrDict或Bunch时,这两个库分别占用了我的请求时间的1/2和1/3(什么!?).这段代码将时间缩短到几乎没有(在0.5ms的范围内).这当然取决于您的需求,
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
Run Code Online (Sandbox Code Playgroud)
请通过/sf/users/49302921/查看此处的原始实施.
另外需要注意的是,这个实现非常简单,并没有实现您可能需要的所有方法.您需要在DictProxy或ListProxy对象上根据需要编写它们.
小智 8
x.__dict__.update(d) 应该没事.
通常,您希望将 dict 层次结构镜像到您的对象中,而不是通常处于最低级别的列表或元组。所以这就是我这样做的方式:
class defDictToObject(object):
def __init__(self, myDict):
for key, value in myDict.items():
if type(value) == dict:
setattr(self, key, defDictToObject(value))
else:
setattr(self, key, value)
Run Code Online (Sandbox Code Playgroud)
所以我们这样做:
myDict = { 'a': 1,
'b': {
'b1': {'x': 1,
'y': 2} },
'c': ['hi', 'bar']
}
Run Code Online (Sandbox Code Playgroud)
并得到:
x.b.b1.x 1
x.c ['嗨','酒吧']
这应该让你开始:
class dict2obj(object):
def __init__(self, d):
self.__dict__['d'] = d
def __getattr__(self, key):
value = self.__dict__['d'][key]
if type(value) == type({}):
return dict2obj(value)
return value
d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
x = dict2obj(d)
print x.a
print x.b.c
print x.d[1].foo
Run Code Online (Sandbox Code Playgroud)
它不适用于列表.您必须将列表包装在UserList中并重载__getitem__以包装dicts.
小智 6
from mock import Mock
d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
my_data = Mock(**d)
# We got
# my_data.a == 1
Run Code Online (Sandbox Code Playgroud)
最简单的方法是使用collections.namedtuple.
我发现以下 4 行最漂亮,它支持嵌套字典:
def dict_to_namedtuple(typename, data):
return namedtuple(typename, data.keys())(
*(dict_to_namedtuple(typename + '_' + k, v) if isinstance(v, dict) else v for k, v in data.items())
)
Run Code Online (Sandbox Code Playgroud)
输出看起来也不错:
>>> nt = dict_to_namedtuple('config', {
... 'path': '/app',
... 'debug': {'level': 'error', 'stream': 'stdout'}
... })
>>> print(nt)
config(path='/app', debug=config_debug(level='error', stream='stdout'))
>>> print(nt.debug.level)
'error'
Run Code Online (Sandbox Code Playgroud)
这也很好用
class DObj(object):
pass
dobj = Dobj()
dobj.__dict__ = {'a': 'aaa', 'b': 'bbb'}
print dobj.a
>>> aaa
print dobj.b
>>> bbb
Run Code Online (Sandbox Code Playgroud)
小智 5
我知道这里已经有很多答案了,我参加聚会很晚,但是这种方法将递归地将“字典”转换成类似对象的结构...在3.xx中有效
def dictToObject(d):
for k,v in d.items():
if isinstance(v, dict):
d[k] = dictToObject(v)
return namedtuple('object', d.keys())(*d.values())
# Dictionary created from JSON file
d = {
'primaryKey': 'id',
'metadata':
{
'rows': 0,
'lastID': 0
},
'columns':
{
'col2': {
'dataType': 'string',
'name': 'addressLine1'
},
'col1': {
'datatype': 'string',
'name': 'postcode'
},
'col3': {
'dataType': 'string',
'name': 'addressLine2'
},
'col0': {
'datatype': 'integer',
'name': 'id'
},
'col4': {
'dataType': 'string',
'name': 'contactNumber'
}
},
'secondaryKeys': {}
}
d1 = dictToObject(d)
d1.columns.col1 # == object(datatype='string', name='postcode')
d1.metadata.rows # == 0
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
228406 次 |
| 最近记录: |