triangulo - reconocimiento de figuras geometricas en python
Convertir el dictado de Python anidado a objeto? (30)
¿Qué hay de simplemente asignar su __dict__
al __dict__
de un objeto vacío?
class Object:
"""If your dict is "flat", this is a simple way to create an object from a dict
>>> obj = Object()
>>> obj.__dict__ = d
>>> d.a
1
"""
pass
Por supuesto, esto falla en su ejemplo de dictado anidado, a menos que recorra el dictado de forma recursiva:
# For a nested dict, you need to recursively update __dict__
def dict2obj(d):
"""Convert a dict to an object
>>> d = {''a'': 1, ''b'': {''c'': 2}, ''d'': ["hi", {''foo'': "bar"}]}
>>> obj = dict2obj(d)
>>> obj.b.c
2
>>> obj.d
["hi", {''foo'': "bar"}]
"""
try:
d = dict(d)
except (TypeError, ValueError):
return d
obj = Object()
for k, v in d.iteritems():
obj.__dict__[k] = dict2obj(v)
return obj
Y su elemento de lista de ejemplo probablemente estaba destinado a ser un Mapping
, una lista de pares (clave, valor) como este:
>>> d = {''a'': 1, ''b'': {''c'': 2}, ''d'': [("hi", {''foo'': "bar"})]}
>>> obj = dict2obj(d)
>>> obj.d.hi.foo
"bar"
Estoy buscando una forma elegante de obtener datos mediante el acceso de atributos en un dictado con algunos dictados y listas anidadas (es decir, sintaxis de objetos de estilo javascript).
Por ejemplo:
>>> d = {''a'': 1, ''b'': {''c'': 2}, ''d'': ["hi", {''foo'': "bar"}]}
Debe 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 recursión, pero ¿cuál sería una buena manera de obtener un estilo de objeto para dicts?
Aprovechando mi respuesta a " Python: ¿Cómo agregar propiedades a una clase de forma dinámica? ":
class data(object):
def __init__(self,*args,**argd):
self.__dict__.update(dict(*args,**argd))
def makedata(d):
d2 = {}
for n in d:
d2[n] = trydata(d[n])
return data(d2)
def trydata(o):
if isinstance(o,dict):
return makedata(o)
elif isinstance(o,list):
return [trydata(i) for i in o]
else:
return o
Llama a makedata
en el diccionario que desea convertir, o tal vez trydata
función de lo que espera como entrada, y escupe un objeto de datos.
Notas:
- Puede agregar elifs a
trydata
si necesita más funcionalidad. - Obviamente esto no funcionará si quieres
xa = {}
o similar. - Si desea una versión de solo lectura, use los datos de clase de la respuesta original .
Aquí hay otra forma de implementar la sugerencia original de SilentGhost:
def dict2obj(d):
if isinstance(d, dict):
n = {}
for item in d:
if isinstance(d[item], dict):
n[item] = dict2obj(d[item])
elif isinstance(d[item], (list, tuple)):
n[item] = [dict2obj(elem) for elem in d[item]]
else:
n[item] = d[item]
return type(''obj_from_dict'', (object,), n)
else:
return d
Aquí hay otra implementación:
class DictObj(object):
def __init__(self, d):
self.__dict__ = d
def dict_to_obj(d):
if isinstance(d, (list, tuple)): return map(dict_to_obj, d)
elif not isinstance(d, dict): return d
return DictObj(dict((k, dict_to_obj(v)) for (k,v) in d.iteritems()))
[Editar] Falta un poco sobre el manejo de los dictados dentro de las listas, no solo otros dictados Corrección añadida.
Creo que un dict consta de número, cadena y dict es suficiente la mayoría del tiempo. Así que ignoro la situación de que las tuplas, listas y otros tipos no aparecen en la dimensión final de un dict.
Teniendo en cuenta la herencia, combinada con la recursividad, soluciona el problema de impresión de manera conveniente y también proporciona dos formas de consultar datos, una forma de editar datos.
Vea el ejemplo a continuación, un dict que describe información sobre los estudiantes:
group=["class1","class2","class3","class4",]
rank=["rank1","rank2","rank3","rank4","rank5",]
data=["name","sex","height","weight","score"]
#build a dict based on the lists above
student_dic=dict([(g,dict([(r,dict([(d,'''') for d in data])) for r in rank ]))for g in group])
#this is the solution
class dic2class(dict):
def __init__(self, dic):
for key,val in dic.items():
self.__dict__[key]=self[key]=dic2class(val) if isinstance(val,dict) else val
student_class=dic2class(student_dic)
#one way to edit:
student_class.class1.rank1[''sex'']=''male''
student_class.class1.rank1[''name'']=''Nan Xiang''
#two ways to query:
print student_class.class1.rank1
print student_class.class1[''rank1'']
print ''-''*50
for rank in student_class.class1:
print getattr(student_class.class1,rank)
Resultados:
{''score'': '''', ''sex'': ''male'', ''name'': ''Nan Xiang'', ''weight'': '''', ''height'': ''''}
{''score'': '''', ''sex'': ''male'', ''name'': ''Nan Xiang'', ''weight'': '''', ''height'': ''''}
--------------------------------------------------
{''score'': '''', ''sex'': '''', ''name'': '''', ''weight'': '''', ''height'': ''''}
{''score'': '''', ''sex'': '''', ''name'': '''', ''weight'': '''', ''height'': ''''}
{''score'': '''', ''sex'': ''male'', ''name'': ''Nan Xiang'', ''weight'': '''', ''height'': ''''}
{''score'': '''', ''sex'': '''', ''name'': '''', ''weight'': '''', ''height'': ''''}
{''score'': '''', ''sex'': '''', ''name'': '''', ''weight'': '''', ''height'': ''''}
Déjame explicarte una solución que casi usé hace algún tiempo. Pero primero, la razón por la que no lo hice se ilustra por el hecho de que el siguiente código:
d = {''from'': 1}
x = dict2obj(d)
print x.from
da este error:
File "test.py", line 20
print x.from == 1
^
SyntaxError: invalid syntax
Debido a que "from" es una palabra clave de Python, hay ciertas claves de diccionario que no puede permitir.
Ahora mi solución permite el acceso a los elementos del diccionario utilizando sus nombres directamente. Pero también te permite usar "semántica de diccionario". Aquí está el código con ejemplo de uso:
class dict2obj(dict):
def __init__(self, dict_):
super(dict2obj, self).__init__(dict_)
for key in self:
item = self[key]
if isinstance(item, list):
for idx, it in enumerate(item):
if isinstance(it, dict):
item[idx] = dict2obj(it)
elif isinstance(item, dict):
self[key] = dict2obj(item)
def __getattr__(self, key):
return self[key]
d = {''a'': 1, ''b'': {''c'': 2}, ''d'': ["hi", {''foo'': "bar"}]}
x = dict2obj(d)
assert x.a == x[''a''] == 1
assert x.b.c == x[''b''][''c''] == 2
assert x.d[1].foo == x[''d''][1][''foo''] == "bar"
Esto debería comenzar tu:
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
Todavía no funciona para las listas. Tendrá que envolver las listas en una Lista de usuarios y sobrecargar __getitem__
para envolver los dictados.
Esto también funciona bien
class DObj(object):
pass
dobj = Dobj()
dobj.__dict__ = {''a'': ''aaa'', ''b'': ''bbb''}
print dobj.a
>>> aaa
print dobj.b
>>> bbb
Hay un ayudante de colección llamado namedtuple
, que puede hacer esto por usted:
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
Me topé con el caso que necesitaba para convertir de forma recursiva una lista de dictados en una lista de objetos, por lo que, según el fragmento de Roberto aquí, ¿qué fue lo que me funcionó?
def dict2obj(d):
if isinstance(d, dict):
n = {}
for item in d:
if isinstance(d[item], dict):
n[item] = dict2obj(d[item])
elif isinstance(d[item], (list, tuple)):
n[item] = [dict2obj(elem) for elem in d[item]]
else:
n[item] = d[item]
return type(''obj_from_dict'', (object,), n)
elif isinstance(d, (list, tuple,)):
l = []
for item in d:
l.append(dict2obj(item))
return l
else:
return d
Tenga en cuenta que cualquier tupla se convertirá a su lista equivalente, por razones obvias.
Espero que esto ayude a alguien tanto como todas sus respuestas lo hicieron por mí, muchachos.
Mi diccionario es de este formato:
addr_bk = {
''person'': [
{''name'': ''Andrew'', ''id'': 123, ''email'': ''[email protected]'',
''phone'': [{''type'': 2, ''number'': ''633311122''},
{''type'': 0, ''number'': ''97788665''}]
},
{''name'': ''Tom'', ''id'': 456,
''phone'': [{''type'': 0, ''number'': ''91122334''}]},
{''name'': ''Jack'', ''id'': 7788, ''email'': ''[email protected]''}
]
}
Como se puede ver, tengo diccionarios anidados y lista de dictados . Esto se debe a que el addr_bk se descodificó a partir de datos de búfer de protocolo que se convirtieron en un dict de python usando lwpb.codec. Hay un campo opcional (por ejemplo, correo electrónico => donde la clave puede no estar disponible) y un campo repetido (por ejemplo, teléfono => convertido a la lista de dict).
Probé todas las soluciones propuestas anteriormente. Algunos no manejan bien los diccionarios anidados. Otros no pueden imprimir los detalles del objeto fácilmente.
Sólo la solución, dict2obj (dict) de Dawie Strauss, funciona mejor.
Lo he mejorado un poco para manejar cuando no se puede encontrar la clave:
# Work the best, with nested dictionaries & lists! :)
# Able to print out all items.
class dict2obj_new(dict):
def __init__(self, dict_):
super(dict2obj_new, self).__init__(dict_)
for key in self:
item = self[key]
if isinstance(item, list):
for idx, it in enumerate(item):
if isinstance(it, dict):
item[idx] = dict2obj_new(it)
elif isinstance(item, dict):
self[key] = dict2obj_new(item)
def __getattr__(self, key):
# Enhanced to handle key not found.
if self.has_key(key):
return self[key]
else:
return None
Entonces, lo probé con:
# Testing...
ab = dict2obj_new(addr_bk)
for person in ab.person:
print "Person ID:", person.id
print " Name:", person.name
# Check if optional field is available before printing.
if person.email:
print " E-mail address:", person.email
# Check if optional field is available before printing.
if person.phone:
for phone_number in person.phone:
if phone_number.type == codec.enums.PhoneType.MOBILE:
print " Mobile phone #:",
elif phone_number.type == codec.enums.PhoneType.HOME:
print " Home phone #:",
else:
print " Work phone #:",
print phone_number.number
Puede aprovechar el módulo json
de la biblioteca estándar con un gancho de objeto personalizado :
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)
Ejemplo de uso:
>>> 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''
Y no es estrictamente de solo lectura como lo es con namedtuple
, es decir, puede cambiar los valores, no la estructura:
>>> o.b.c = 3
>>> o.b.c
3
Qué tal esto:
from functools import partial
d2o=partial(type, "d2o", ())
Esto puede ser usado así:
>>> o=d2o({"a" : 5, "b" : 3})
>>> print o.a
5
>>> print o.b
3
Quería subir mi versión de este pequeño paradigma.
class Struct(dict):
def __init__(self,data):
for key, value in data.items():
if isinstance(value, dict):
setattr(self, key, Struct(value))
else:
setattr(self, key, type(value).__init__(value))
dict.__init__(self,data)
Conserva los atributos para el tipo que se importa a la clase. Mi única preocupación sería sobrescribir los métodos desde el diccionario de su análisis. ¡Pero por lo demás parece sólido!
Sé que ya hay muchas respuestas aquí y llego tarde a la fiesta, pero este método recursivamente convertirá un diccionario en una estructura similar a un objeto ... Funciona en 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
Si desea acceder a las teclas dict como un objeto (o como un dict para teclas difíciles), hágalo de forma recursiva, y también podrá actualizar el dict original, podría hacer lo siguiente:
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)
Ejemplo de uso:
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''}}
Si su json.loads()
proviene de json.loads()
, puede convertirlo en un objeto (en lugar de un dictado) en una línea:
import json
from collections import namedtuple
json.loads(data, object_hook=lambda d: namedtuple(''X'', d.keys())(*d.values()))
Vea también Cómo convertir datos JSON en un objeto Python .
Sorprendentemente nadie ha mencionado a Bunch . Esta biblioteca está diseñada exclusivamente para proporcionar acceso de estilo de atributo a objetos dict 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''
Una biblioteca de Python 3 está disponible en https://github.com/Infinidat/munch - El crédito va a codyzu
Terminé probando AMBAS bibliotecas AttrDict y Bunch y encontré que eran demasiado lentas para mis usos. Después de que un amigo y yo lo investigamos, encontramos que el método principal para escribir estas bibliotecas resulta en que la biblioteca se repita de forma agresiva a través de un objeto anidado y haga copias del objeto del diccionario en todo momento. Con esto en mente, hicimos dos cambios clave. 1) Hicimos los atributos con carga perezosa 2) En lugar de crear copias de un objeto de diccionario, creamos copias de un objeto de proxy ligero. Esta es la implementación final. El aumento de rendimiento de usar este código es increíble. Cuando utilizo AttrDict o Bunch, estas dos bibliotecas solo consumieron 1/2 y 1/3 respectivamente de mi tiempo de solicitud (¿¡qué !?). Este código redujo ese tiempo a casi nada (en algún lugar dentro del rango de 0.5 ms). Por supuesto, esto depende de sus necesidades, pero si está usando esta funcionalidad en su código, definitivamente use algo tan simple como este.
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
Vea la implementación original here en https://.com/users/704327/michael-merickel .
La otra cosa a tener en cuenta es que esta implementación es bastante simple y no implementa todos los métodos que pueda necesitar. Deberá escribirlos según sea necesario en los objetos DictProxy o ListProxy.
Tomando lo que creo que son los mejores aspectos de los ejemplos anteriores, esto es lo que se me ocurrió:
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()))
Tuve algunos problemas con __getattr__
no ser llamado, así que construí una nueva versión de clase de estilo:
class Struct(object):
''''''The recursive class for building and representing objects with.''''''
class NoneStruct(object):
def __getattribute__(*args):
return Struct.NoneStruct()
def __eq__(self, obj):
return obj == None
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 __getattribute__(*args):
try:
return object.__getattribute__(*args)
except:
return Struct.NoneStruct()
def __repr__(self):
return ''{%s}'' % str('', ''.join(''%s : %s'' % (k, repr(v)) for
(k, v) in self.__dict__.iteritems()))
Esta versión también tiene la adición de NoneStruct
que se devuelve cuando se llama a un atributo que no está establecido. Esto permite que la prueba Ninguna vea si un atributo está presente. Muy útil cuando no se conoce la entrada exacta del dict (configuración, etc.).
bla = Struct({''a'':{''b'':1}})
print(bla.a.b)
>> 1
print(bla.a.c == None)
>> True
Viejo Q&A, pero tengo algo más que hablar. Parece que nadie habla de dictados recursivos. Este es mi código:
#!/usr/bin/env python
class Object( dict ):
def __init__( self, data = None ):
super( Object, self ).__init__()
if data:
self.__update( data, {} )
def __update( self, data, did ):
dataid = id(data)
did[ dataid ] = self
for k in data:
dkid = id(data[k])
if did.has_key(dkid):
self[k] = did[dkid]
elif isinstance( data[k], Object ):
self[k] = data[k]
elif isinstance( data[k], dict ):
obj = Object()
obj.__update( data[k], did )
self[k] = obj
obj = None
else:
self[k] = data[k]
def __getattr__( self, key ):
return self.get( key, None )
def __setattr__( self, key, value ):
if isinstance(value,dict):
self[key] = Object( value )
else:
self[key] = value
def update( self, *args ):
for obj in args:
for k in obj:
if isinstance(obj[k],dict):
self[k] = Object( obj[k] )
else:
self[k] = obj[k]
return self
def merge( self, *args ):
for obj in args:
for k in obj:
if self.has_key(k):
if isinstance(self[k],list) and isinstance(obj[k],list):
self[k] += obj[k]
elif isinstance(self[k],list):
self[k].append( obj[k] )
elif isinstance(obj[k],list):
self[k] = [self[k]] + obj[k]
elif isinstance(self[k],Object) and isinstance(obj[k],Object):
self[k].merge( obj[k] )
elif isinstance(self[k],Object) and isinstance(obj[k],dict):
self[k].merge( obj[k] )
else:
self[k] = [ self[k], obj[k] ]
else:
if isinstance(obj[k],dict):
self[k] = Object( obj[k] )
else:
self[k] = obj[k]
return self
def test01():
class UObject( Object ):
pass
obj = Object({1:2})
d = {}
d.update({
"a": 1,
"b": {
"c": 2,
"d": [ 3, 4, 5 ],
"e": [ [6,7], (8,9) ],
"self": d,
},
1: 10,
"1": 11,
"obj": obj,
})
x = UObject(d)
assert x.a == x["a"] == 1
assert x.b.c == x["b"]["c"] == 2
assert x.b.d[0] == 3
assert x.b.d[1] == 4
assert x.b.e[0][0] == 6
assert x.b.e[1][0] == 8
assert x[1] == 10
assert x["1"] == 11
assert x[1] != x["1"]
assert id(x) == id(x.b.self.b.self) == id(x.b.self)
assert x.b.self.a == x.b.self.b.self.a == 1
x.x = 12
assert x.x == x["x"] == 12
x.y = {"a":13,"b":[14,15]}
assert x.y.a == 13
assert x.y.b[0] == 14
def test02():
x = Object({
"a": {
"b": 1,
"c": [ 2, 3 ]
},
1: 6,
2: [ 8, 9 ],
3: 11,
})
y = Object({
"a": {
"b": 4,
"c": [ 5 ]
},
1: 7,
2: 10,
3: [ 12 , 13 ],
})
z = {
3: 14,
2: 15,
"a": {
"b": 16,
"c": 17,
}
}
x.merge( y, z )
assert 2 in x.a.c
assert 3 in x.a.c
assert 5 in x.a.c
assert 1 in x.a.b
assert 4 in x.a.b
assert 8 in x[2]
assert 9 in x[2]
assert 10 in x[2]
assert 11 in x[3]
assert 12 in x[3]
assert 13 in x[3]
assert 14 in x[3]
assert 15 in x[2]
assert 16 in x.a.b
assert 17 in x.a.c
if __name__ == ''__main__'':
test01()
test02()
x.__dict__.update(d)
debería funcionar bien.
Actualización: en Python 2.6 y en adelante, considere si la estructura de datos de namedtuple
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
>>> 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''
class Struct(dict):
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name, value):
self[name] = value
def copy(self):
return Struct(dict.copy(self))
Uso:
points = Struct(x=1, y=2)
# Changing
points[''x''] = 2
points.y = 1
# Accessing
points[''x''], points.x, points.get(''x'') # 2 2 2
points[''y''], points.y, points.get(''y'') # 1 1 1
# Accessing inexistent keys/attrs
points[''z''] # KeyError: z
points.z # AttributeError: z
# Copying
points_copy = points.copy()
points.x = 2
points_copy.x # 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
Se puede utilizar con cualquier estructura de secuencia / dict / valor de cualquier profundidad.
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''
from mock import Mock
d = {''a'': 1, ''b'': {''c'': 2}, ''d'': ["hi", {''foo'': "bar"}]}
my_data = Mock(**d)
# We got
# my_data.a == 1
x = type(''new_dict'', (object,), d)
Luego agrega recursión 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''