Question Convertir un dict Python imbriqué en objet?


Je suis à la recherche d'une manière élégante d'obtenir des données en utilisant l'accès aux attributs sur une dict avec des dicts imbriqués et des listes (c'est-à-dire une syntaxe d'objet de type javascript).

Par exemple:

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

Devrait être accessible de cette manière:

>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar

Je pense que ce n'est pas possible sans récursivité, mais quelle serait une bonne façon d'obtenir un style d'objet pour les dicts?


444
2017-08-20 11:28


origine


Réponses:


Mettre à jour: Dans Python 2.6 et suivants, déterminez si le namedtuple structure de données adaptée à vos besoins:

>>> 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']

L'alternative (contenu de la réponse d'origine) est:

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

Ensuite, vous pouvez utiliser:

>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2

592
2017-08-20 11:55



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'

87
2017-08-20 11:58



Étonnamment, personne n'a mentionné Bouquet. Cette librairie est exclusivement destinée à fournir un accès de type attribut aux objets dict et fait exactement ce que l'OP veut. Une démonstration:

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

Une bibliothèque Python 3 est disponible sur https://github.com/Infinidat/munch - Le crédit va à codyzu


73
2017-07-20 16:30



x = type('new_dict', (object,), d)

puis ajoutez la récursivité à ceci et vous avez terminé.

modifier voici comment je le mettrais en œuvre:

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

55
2017-08-20 11:31



Il y a un assistant de collecte appelé namedtuple, cela peut le faire pour vous:

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

40
2018-02-23 12:43



Prenant ce que je ressens sont les meilleurs aspects des exemples précédents, voici ce que j'ai trouvé:

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

29
2017-07-04 16:12



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

Peut être utilisé avec n'importe quelle structure de séquence / dict / valeur de n'importe quelle profondeur.


26
2017-08-09 08:58