¿Cómo convertir un dictado de Python anidado en un objeto?

Resuelto Marc asked hace 15 años • 45 respuestas

Estoy buscando una forma elegante de obtener datos mediante el acceso a atributos en un dictado con algunos dictados y listas anidados (es decir, sintaxis de objetos de estilo javascript).

Por ejemplo:

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

Debería ser accesible de esta manera:

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

Creo que esto no es posible sin recursividad, pero ¿cuál sería una buena manera de obtener un estilo de objeto para dictados?

Marc avatar Aug 20 '09 18:08 Marc
Aceptado

Actualización: en Python 2.6 y posteriores, considere si la namedtupleestructura de datos se adapta a sus necesidades:

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

La alternativa (contenido de la respuesta original) es:

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

Entonces, puedes usar:

>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2
Eli Bendersky avatar Aug 20 '2009 11:08 Eli Bendersky

Sorprendentemente nadie ha mencionado a Bunch . Esta biblioteca está destinada exclusivamente a proporcionar acceso de estilo de atributo a objetos de dictado y hace exactamente lo que quiere el OP. Una demostración:

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

Hay una biblioteca de Python 3 disponible en https://github.com/Infinidat/munch - El crédito es para codyzu

>>> 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'
Arif Amirani avatar Jul 20 '2014 16:07 Arif Amirani
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'
Nadia Alramli avatar Aug 20 '2009 11:08 Nadia Alramli
x = type('new_dict', (object,), d)

luego agrega recursividad a esto y listo.

editar así es como lo implementaría:

>>> 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'
SilentGhost avatar Aug 20 '2009 11:08 SilentGhost