[python] 중첩 된 Python dict를 객체로 변환 하시겠습니까?

중첩 된 dicts 및 list가있는 dict의 속성 액세스를 사용하여 데이터를 얻는 우아한 방법을 찾고 있습니다 (예 : javascript 스타일 객체 구문).

예를 들면 다음과 같습니다.

>>> 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에 대한 객체 스타일을 얻는 좋은 방법은 무엇입니까?



답변

업데이트 : 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


답변

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'


답변

놀랍게도 아무도 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'

Python 3 라이브러리는 https://github.com/Infinidat/munch에 있습니다. 크레딧은 codyzu 로 이동합니다


답변

x = 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'


답변

이라는 컬렉션 도우미 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


답변

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

모든 깊이의 시퀀스 / dict / value 구조와 함께 사용할 수 있습니다.


답변

필자가 이전 예제의 가장 좋은 측면이라고 생각하는 것을 생각해 봅시다.

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()))