Convert nested Python dict to object?

后端 未结 30 1932
时光取名叫无心
时光取名叫无心 2020-11-22 09:28

I\'m searching for an elegant way to get data using attribute access on a dict with some nested dicts and lists (i.e. javascript-style object syntax).

For example:

相关标签:
30条回答
  • 2020-11-22 10:18

    There's a collection helper called namedtuple, that can do this for you:

    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
    
    0 讨论(0)
  • 2020-11-22 10:18

    This should get your started:

    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
    

    It doesn't work for lists, yet. You'll have to wrap the lists in a UserList and overload __getitem__ to wrap dicts.

    0 讨论(0)
  • 2020-11-22 10:19

    Taking what I feel are the best aspects of the previous examples, here's what I came up with:

    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()))
    
    0 讨论(0)
  • 2020-11-22 10:19

    If you want to access dict keys as an object (or as a dict for difficult keys), do it recursively, and also be able to update the original dict, you could do:

    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)
    

    Example usage:

    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'}}
    
    0 讨论(0)
  • 2020-11-22 10:20

    x.__dict__.update(d) should do fine.

    0 讨论(0)
  • 2020-11-22 10:21
    >>> 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'
    
    0 讨论(0)
提交回复
热议问题