¿Cómo hago que los miembros del diccionario Python sean accesibles a través de un punto "."?
Por ejemplo, en lugar de escribir mydict['val']
, me gustaría escribir mydict.val
.
También me gustaría acceder a los dictados anidados de esta manera. Por ejemplo
mydict.mydict2.val
se referiría a
mydict = { 'mydict2': { 'val': ... } }
python
dictionary
syntax
nested
bodacydo
fuente
fuente
d[a][b][c]
se reemplaza pord[a, b, c]
.{"my.key":"value"}
? ¿O cuando la clave es una palabra clave, como "desde"? Lo he considerado un par de veces, y son más problemas y resolución de problemas que beneficios percibidos.Respuestas:
Puedes hacerlo usando esta clase que acabo de hacer. Con esta clase, puede usar el
Map
objeto como otro diccionario (incluida la serialización json) o con la notación de puntos. Espero poder ayudarte:Ejemplos de uso:
fuente
.iteritems()
a.items()
AttributeError
si el atributo no existe. En cambio, volveráNone
.self.update(*args,**kwargs)
. Además, puedes agregar__missing__(self,key): value=self[key]= type(self)(); return value
. Luego puede agregar entradas faltantes utilizando la notación de puntos. Si desea que sea seleccionable, puede agregar__getstate__
y__setstate__
hasattr(Map, 'anystring') is true. which means the hasattr would always return True due to overriding
__getattr__`Siempre he guardado esto en un archivo util. También puedes usarlo como mezcla en tus propias clases.
fuente
d = {'foo': {'bar': 'baz'}}; d = dotdict(d); d.foo.bar
arroja un error de atributo, perod.foo
funciona bien.python class DotDict(dict): """dot.notation access to dictionary attributes""" def __getattr__(*args): val = dict.get(*args) return DotDict(val) if type(val) is dict else val __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__
get
ser una mala idea, ya que volverá enNone
lugar de generar un error por elementos faltantes ...Instalar a
dotmap
través depip
Hace todo lo que quieres que haga y subclases
dict
, por lo que funciona como un diccionario normal:Además de eso, puede convertirlo hacia y desde
dict
objetos:Esto significa que si algo a lo que desea acceder ya está en
dict
forma, puede convertirlo en unDotMap
acceso fácil:Finalmente, crea automáticamente nuevas
DotMap
instancias secundarias para que pueda hacer cosas como esta:Comparación con Bunch
Divulgación completa: soy el creador del DotMap . Lo creé porque
Bunch
faltaban estas característicasDotMap
creación secundaria automática , lo que ahorra tiempo y crea un código más limpio cuando tiene mucha jerarquíadict
ay convirtiendo recursivamente todas lasdict
instancias secundarias aDotMap
fuente
{"test.foo": "bar"}
Se puede acceder a través demymap.test.foo
Eso sería fantástico. Se necesitará cierta regresión para convertir un mapa plano en un mapa profundo y luego aplicarle DotMap, ¡pero vale la pena!DotMap
con autocompletar funciona mejor. Uso Sublime Text, que autocompleta palabras clave escritas previamente.**kwargs
oc = {**a, **b}
. De hecho, falla silenciosamente, se comporta como un diccionario vacío cuando se extrae.m = DotMap(); m.a = 2; m.b = 3; print('{a} {b}'.format(**m));
y obtuve lo esperado2 3
. Si tiene un caso roto comprobado que funcionadict()
pero noDotMap()
, envíe su código a la pestaña Problemas en GitHub.Derivar de dict e implementar
__getattr__
e__setattr__
.O puede usar Bunch, que es muy similar.
No creo que sea posible monopatch incorporado en la clase dict.
fuente
Fabric tiene una implementación realmente agradable y mínima . Extendiendo eso para permitir el acceso anidado, podemos usar a
defaultdict
, y el resultado se ve así:Haz uso de la siguiente manera:
Eso explica un poco la respuesta de Kugel de "Derivar de dict e implementar
__getattr__
e__setattr__
". ¡Ahora ya sabes cómo!fuente
dotdict
que permite convertirdict
objetos existentes de forma recursiva: gist.github.com/miku/…Intenté esto:
Puedes intentarlo
__getattribute__
también.hacer que cada dict sea un tipo de dotdict sería lo suficientemente bueno, si desea iniciar esto desde un dict multicapa, intente implementar
__init__
también.fuente
def docdict(name):
antes y luego `if isinstance (name, dict): return DotDict (name) return name`class dotdict(dict): def __getattr__(self, name): if name not in self: return None elif type(self[name]) is dict: return JsonDot(self[name]) else: return self[name]
No lo hagas El acceso al atributo y la indexación son cosas separadas en Python, y no debe desear que realicen lo mismo. Haga una clase (posiblemente una hecha por
namedtuple
) si tiene algo que debería tener atributos accesibles y use[]
notación para obtener un elemento de un dict.fuente
.
lugar de[]
acceder a estructuras de datos complicadas en las plantillas de Mako.Si desea encurtir su diccionario modificado, debe agregar algunos métodos de estado a las respuestas anteriores:
fuente
__getattr__ = dict.get
Sobre la base de la respuesta de Kugel y teniendo en cuenta las palabras de precaución de Mike Graham, ¿qué pasa si hacemos un envoltorio?
fuente
Uso
SimpleNamespace
:fuente
Me gusta el Munch y ofrece muchas opciones prácticas además del acceso de punto.
fuente
Recientemente me encontré con la biblioteca ' Box ' que hace lo mismo.
Comando de instalación:
pip install python-box
Ejemplo:
Descubrí que es más efectivo que otras bibliotecas existentes como dotmap, que generan un error de recursión de Python cuando tienes grandes dictados anidados.
Enlace a la biblioteca y detalles: https://pypi.org/project/python-box/
fuente
Uso
__getattr__
, muy simple, funciona en Python 3.4.3Salida:
fuente
El lenguaje en sí no es compatible con esto, pero a veces sigue siendo un requisito útil. Además de la receta Bunch, también puede escribir un pequeño método que puede acceder a un diccionario usando una cadena de puntos:
que apoyaría algo como esto:
fuente
Para construir sobre la respuesta de epool, esta versión le permite acceder a cualquier dict a través del operador de punto:
Por ejemplo,
foo.bar.baz[1].baba
vuelve"loo"
.fuente
iteritems()
conitems()
yxrange()
conrange()
Si uno decide convertirlo permanentemente
dict
en un objeto, esto debería hacerlo. Puede crear un objeto desechable justo antes de acceder.fuente
Terminé probando AMBOS el AttrDict y el Bunchbibliotecas y descubrí que son una forma lenta 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 de 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 sus necesidades, pero si está utilizando esta funcionalidad bastante en su código,
Ver 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
Me gustaría lanzar mi propia solución al ring:
https://github.com/skorokithakis/jsane
Le permite analizar JSON en algo a lo que puede acceder
with.attribute.lookups.like.this.r()
, principalmente porque no había visto esta respuesta antes de comenzar a trabajar en ella.fuente
KeyError
es uno de ellos. Cuando se accede a la clave que no existe, todo lo que tiene que hacer es regresar de maneraNone
similar al comportamiento de JS. Soy un gran admirador de la autovivificación tanto para leer como para escribir. Tu biblioteca está más cerca del ideal.No es una respuesta directa a la pregunta del OP, pero está inspirada y puede ser útil para algunos. He creado una solución basada en objetos utilizando el
__dict__
código interno (de ninguna manera optimizado)fuente
Una forma sencilla de obtener acceso a puntos (pero no acceso a matriz) es utilizar un objeto plano en Python. Me gusta esto:
... y úsalo así:
... para convertirlo en un dict:
fuente
Esta solución es una mejora sobre la que ofrece epool para abordar el requisito del OP para acceder a los dictados anidados de manera consistente. La solución de epool no permitió acceder a los dictados anidados.
Con esta clase, ahora se puede hacer algo como:
A.B.C.D
.fuente
Esto también funciona con dictados anidados y asegura que los dictados que se agregan más adelante se comporten de la misma manera:
fuente
La respuesta de @ derek73 es muy clara, pero no se puede encurtir ni copiar (en profundidad), y regresa
None
por las teclas que faltan. El siguiente código soluciona esto.Editar: No vi la respuesta anterior que aborda exactamente el mismo punto (votado a favor). Dejo la respuesta aquí como referencia.
fuente
Una solución algo delicada
fuente