Estoy buscando una manera elegante de obtener datos usando el acceso a atributos en un dict 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"}]}
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 recurrencia, pero ¿cuál sería una buena manera de obtener un estilo de objeto para los dictados?
python
object
dictionary
Bagazo
fuente
fuente
from_
en lugar de_from
según PEP 8 .getattr(x, 'from')
lugar de renombrar el atributo.d1.b.c
), creo que está claro que debería usar algo de una biblioteca, por ejemplo, namedtuple de colecciones , como sugiere esta respuesta , ... .Respuestas:
Actualización: en Python 2.6 y versiones posteriores, considere si la
namedtuple
estructura de datos se adapta a sus necesidades:La alternativa (contenido de la respuesta original) es:
Entonces, puedes usar:
fuente
Struct
s anidados a partir de diccionarios anidados, pero en general el tipo de valor puede ser cualquier cosa. La clave se limita a ser adecuada para una ranura de objetoargparse.Namespace
(que también tiene definidos__eq__
,__ne__
,__contains__
).fuente
if isinstance(b, (list, tuple)):
obj
clase herede deargparse.Namespace
características adicionales como representación de cadena legible.Sorprendentemente, nadie ha mencionado Bunch . Esta biblioteca está destinada exclusivamente a proporcionar acceso de estilo de atributo a objetos dictados y hace exactamente lo que quiere el OP. Una demostración:
Una biblioteca de Python 3 está disponible en https://github.com/Infinidat/munch - El crédito va a codyzu
fuente
luego agrega recursividad a esto y listo.
editar así es como lo implementaría:
fuente
top_instance = top()
y devolver eso donde regresastop
?x
yx.b
que vuelven feas<class '__main__.new'>
Hay un asistente de recolección llamado
namedtuple
, que puede hacer esto por usted:fuente
Se puede usar con cualquier secuencia / dict / estructura de valor de cualquier profundidad.
fuente
def __repr__(self): return '{%s}' % str(', '.join("'%s': %s" % (k, repr(v)) for (k, v) in self.__dict__.iteritems()))
.items()
lugar de.iteritems()
en la línea 4. (La función fue renombrada, pero esencialmente es la misma )Tomando lo que siento son los mejores aspectos de los ejemplos anteriores, esto es lo que se me ocurrió:
fuente
def __init__(self, dct): for k, v in dct.iteritems(): setattr(self, k, isinstance(v, dict) and self.__class__(v) or v)
que también elimina la llamada explícita aStruct
isinstance(v, dict)
cheque sería mejor, yaisinstance(v, collections.Mapping)
que puede manejar futuras cosas como dictSi su dict proviene
json.loads()
, puede convertirlo en un objeto (en lugar de un dict) en una línea:Consulte también Cómo convertir datos JSON en un objeto Python .
fuente
.loads
si tienes un gran objeto JSONSi desea acceder a las claves dict como un objeto (o como un dict para claves difíciles), hágalo de forma recursiva y también pueda actualizar el dict original, puede hacer lo siguiente:
Ejemplo de uso:
fuente
fuente
Terminé probando AMBOS el AttrDict y el Bunchbibliotecas y descubrí que eran demasiado lentas para mis usos. Después de que un amigo y yo lo investigamos, descubrimos que el método principal para escribir estas bibliotecas hace que la biblioteca recurra agresivamente 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) Creamos atributos con carga lenta 2) en lugar de crear copias de un objeto de diccionario, creamos copias de un objeto proxy liviano. Esta es la implementación final. El aumento del rendimiento del uso de este código es increíble. Al usar 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 en el rango de 0.5ms). Por supuesto, esto depende de tus necesidades,
Vea la implementación original aquí por https://stackoverflow.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.
fuente
x.__dict__.update(d)
debería hacerlo bienfuente
__dict__
: pruebaobject().__dict__
y obtendrásAttributeError: 'object' object has no attribute '__dict__'
Puede aprovechar el
json
módulo de la biblioteca estándar con un enlace de objeto personalizado :Ejemplo de uso:
Y no es estrictamente de solo lectura como es
namedtuple
, es decir, puede cambiar los valores, no la estructura:fuente
json.JSONEncoder
yobject_hook
.Esto debería comenzar:
No funciona para listas, todavía. Tendrá que ajustar las listas en una Lista de usuarios y sobrecargarlas
__getitem__
para ajustar los dictados.fuente
if isinstance(d, list)
cláusula deAnon
la respuesta de.Sé que ya hay muchas respuestas aquí y llego tarde a la fiesta, pero este método convertirá recursivamente y 'en su lugar' un diccionario a una estructura similar a un objeto ... Funciona en 3.xx
fuente
fuente
Déjame explicarte una solución que casi utilicé 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:
da este error:
Debido a que "from" es una palabra clave de Python, hay ciertas teclas 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 le permite usar "semántica de diccionario". Aquí está el código con ejemplo de uso:
fuente
Preguntas y respuestas anteriores, pero tengo algo más de qué hablar. Parece que nadie habla de dict recursivo. Este es mi código:
fuente
Quería subir mi versión de este pequeño paradigma.
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!
fuente
df.a
ni siquiera funciona.Esto también funciona bien
fuente
Aquí hay otra forma de implementar la sugerencia original de SilentGhost:
fuente
Me topé con el caso que necesitaba para convertir de forma recursiva una lista de dictados en una lista de objetos, así que basándome en el fragmento de Roberto aquí, ¿qué funcionó para mí?
Tenga en cuenta que cualquier tupla se convertirá en su lista equivalente, por razones obvias.
Espero que esto ayude a alguien tanto como todas sus respuestas me ayudaron, muchachos.
fuente
¿Qué hay de solo asignarle
dict
a__dict__
un objeto vacío?Por supuesto, esto falla en su ejemplo de dict anidado a menos que recorra el dict recursivamente:
Y su elemento de lista de ejemplo probablemente estaba destinado a ser
Mapping
una lista de pares (clave, valor) como este:fuente
Aquí hay otra implementación:
[Editar] Se perdió un poco sobre el manejo de dictados dentro de las listas, no solo otros dictados. Se agregó una solución.
fuente
Uso:
fuente
Qué tal esto:
Esto se puede usar así:
fuente
Creo que un dict consiste en número, cadena y dict es suficiente la mayoría del tiempo. Así que ignoro la situación en la que tuplas, listas y otros tipos no aparecen en la dimensión final de un dict.
Teniendo en cuenta la herencia, combinada con la recursividad, resuelve el problema de impresión convenientemente y también proporciona dos formas de consultar datos, una forma de editarlos.
Vea el siguiente ejemplo, un dict que describe información sobre los estudiantes:
Resultados:
fuente
Por lo general, desea reflejar la jerarquía dict en su objeto, pero no la lista o las tuplas que generalmente están en el nivel más bajo. Así es como hice esto:
Entonces hacemos:
y obten:
x.b.b1.x
1x.c
['hola', 'bar']fuente
Mi diccionario es de este formato:
Como se puede ver, he anidado diccionarios y una lista de dictados . Esto se debe a que addr_bk se decodificó a partir de los datos del búfer de protocolo que se convirtió en un dict 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.
Solo la solución, dict2obj (dict) de Dawie Strauss, funciona mejor.
Lo he mejorado un poco para manejar cuando no se puede encontrar la clave:
Luego, lo probé con:
fuente
Partiendo de mi respuesta a " python: ¿Cómo agregar propiedades a una clase dinámicamente? ":
Invoca
makedata
el diccionario que deseas convertir, o tal veztrydata
dependiendo de lo que esperas como entrada, y escupe un objeto de datos.Notas:
trydata
si necesita más funcionalidad.x.a = {}
o similar.fuente