Tengo un diccionario anidado. ¿Hay una sola forma de obtener valores de forma segura?
try:
example_dict['key1']['key2']
except KeyError:
pass
¿O tal vez Python tiene un método como get()
para diccionario anidado?
python
dictionary
methods
except
Arti
fuente
fuente
except keyerror:
cláusula.Respuestas:
Puedes usar
get
dos veces:Esto volverá
None
si existekey1
okey2
no existe.Tenga en cuenta que esto aún podría generar un
AttributeError
ifexample_dict['key1']
, pero no es un dict (o un objeto similar a un dict con unget
método). Eltry..except
código que publicó generaría unTypeError
lugar si noexample_dict['key1']
se puede suscribir.Otra diferencia es que los
try...except
cortocircuitos inmediatamente después de la primera clave faltante. La cadena deget
llamadas no.Si desea preservar la sintaxis,
example_dict['key1']['key2']
pero no desea que aumente nunca KeyErrors, puede usar la receta Hasher :Tenga en cuenta que esto devuelve un Hasher vacío cuando falta una clave.
Dado que
Hasher
es una subclase dedict
usted, puede usar un Hasher de la misma manera que podría usar undict
. Todos los mismos métodos y sintaxis están disponibles, Hashers solo trata las claves faltantes de manera diferente.Puede convertir una regular
dict
en unaHasher
como esta:y convierta a
Hasher
a regular con ladict
misma facilidad:Otra alternativa es ocultar la fealdad en una función auxiliar:
Entonces, el resto de su código puede permanecer relativamente legible:
fuente
safeget
muchos sentidos, el método no es muy seguro, ya que sobrescribe el diccionario original, lo que significa que no puede hacer cosas con seguridadsafeget(dct, 'a', 'b') or safeget(dct, 'a')
.safeget
nunca sobrescribe el diccionario original. Devolverá el diccionario original, un valor del diccionario original oNone
.dct = dct[key]
reasigna un nuevo valor a la variable localdct
. Esto no muta el dict original (por lo que el dict original no se ve afectado porsafeget
). Si, por otro lado, sedct[key] = ...
hubiera utilizado, entonces el dict original se habría modificado. En otras palabras, en Python los nombres están vinculados a valores . Asignación de un nuevo valor a un nombre no afecta el valor de edad (a menos que ya no hay más referencias al antiguo valor, en cuyo caso (en CPython) que conseguirá basura recogida.)También podría usar python reduce :
fuente
Al combinar todas estas respuestas aquí y los pequeños cambios que hice, creo que esta función sería útil. Es seguro, rápido y fácil de mantener.
Ejemplo:
fuente
deep_get({'a': 1}, "a.b")
daNone
pero esperaría una excepción comoKeyError
o algo más.None
aRaise KeyError
A partir de la respuesta de Yoav, un enfoque aún más seguro:
fuente
Una solución recursiva. No es el más eficiente, pero me parece un poco más legible que los otros ejemplos y no se basa en functools.
Ejemplo
Una versión más pulida.
fuente
Si bien el enfoque de reducción es ordenado y breve, creo que un bucle simple es más fácil de asimilar. También he incluido un parámetro predeterminado.
Como ejercicio para comprender cómo funcionaba la reducción de una línea, hice lo siguiente. Pero en última instancia, el enfoque de bucle me parece más intuitivo.
Uso
fuente
Te sugiero que pruebes
python-benedict
.Es un
dict
subclase que proporciona soporte de keypath y mucho más.Instalación:
pip install python-benedict
ahora puede acceder a valores anidados utilizando keypath :
o acceder a valores anidados utilizando la lista de claves :
Está bien probado y de código abierto en GitHub :
https://github.com/fabiocaccamo/python-benedict
fuente
d.get('a.b[0].c[-1]')
Una clase simple que puede ajustar un dict y recuperar en función de una clave:
Por ejemplo:
Si la clave no existe, regresa
None
por defecto. Puede anular eso usando unadefault=
clave en elFindDict
contenedor, por ejemplo`:fuente
para una recuperación de clave de segundo nivel, puede hacer esto:
fuente
Después de ver esto para obtener atributos profundos, hice lo siguiente para obtener
dict
valores anidados de manera segura usando la notación de puntos. Esto funciona para mí porquedicts
son objetos MongoDB deserializados, así que sé que los nombres de las claves no contienen.
s. Además, en mi contexto, puedo especificar un valor de respaldo falso (None
) que no tengo en mis datos, por lo que puedo evitar el patrón try / except al llamar a la función.fuente
fallback
en realidad no se usa en la función..
sep=','
palabra clave arg para generalizar para determinadas condiciones (sep, fallback). Y @denvar, siobj
se dice de tipoint
después de una secuencia de reducción, entonces obj [nombre] genera un TypeError, que atrapo. Si usé obj.get (name) u obj.get (name, fallback) en su lugar, generaría un AttributeError, por lo que de cualquier manera tendría que atraparlo.Otra función para la misma cosa, también devuelve un valor booleano para representar si se encontró la clave o no y maneja algunos errores inesperados.
ejemplo de uso:
fuente
Puedes usar pydash:
https://pydash.readthedocs.io/en/latest/api.html
fuente
Una adaptación de la respuesta de unutbu que encontré útil en mi propio código:
Genera una entrada de diccionario para la clave1 si aún no tiene esa clave para evitar KeyError. Si quieres terminar un diccionario anidado que incluye ese emparejamiento de teclas de todos modos como lo hice yo, esta parece ser la solución más fácil.
fuente
Dado que es razonable hacer un error de clave si falta una de las claves, incluso no podemos verificarlo y obtenerlo de la siguiente manera:
fuente
Poca mejora en el
reduce
enfoque para que funcione con la lista. También se utiliza la ruta de datos como cadena dividida por puntos en lugar de matriz.fuente
Una solución que he usado que es similar al doble get pero con la capacidad adicional de evitar un TypeError usando la lógica if else:
Sin embargo, cuanto más anidado está el diccionario, más engorroso se vuelve.
fuente
Para búsquedas anidadas de diccionario / JSON, puede usar dictor
pip install dictor
objeto dict
para obtener los elementos de Lonestar, simplemente proporcione una ruta separada por puntos, es decir
puede proporcionar un valor de reserva en caso de que la clave no esté en la ruta
Hay muchas más opciones que puedes hacer, como ignorar el uso de mayúsculas y minúsculas y usar otros caracteres además de '.' como un separador de ruta,
https://github.com/perfecto25/dictor
fuente
Cambié poco esta respuesta. Agregué verificar si estamos usando la lista con números. Así que ahora podemos usarlo de cualquier manera.
deep_get(allTemp, [0], {})
odeep_get(getMinimalTemp, [0, minimalTemperatureKey], 26)
etc.fuente
Ya hay muchas buenas respuestas, pero se me ocurrió una función llamada get similar to lodash get en JavaScript land que también permite acceder a las listas por índice:
fuente