No devolver ninguno si la clave del diccionario no está disponible

490

Necesito una forma de obtener un valor de diccionario si su clave existe, o simplemente regresar None, si no existe.

Sin embargo, Python genera una KeyErrorexcepción si busca una clave que no existe. Sé que puedo verificar la clave, pero estoy buscando algo más explícito. ¿Hay alguna manera de regresar Nonesi la clave no existe?

Spyros
fuente
74
Solo use en .get(key)lugar de[key]
Gabe
12
Un dict genera una excepción KeyError. No "devuelve key_error".
Ber
3
Acceder a la clave y capturar la excepción está perfectamente bien en Python. Incluso es un patrón de diseño muy conocido y usado. Si en su lugar devuelve None, se hace imposible almacenar None como valor, lo que puede ser relevante en algunos casos.
Ber
1
A veces, desea tratar las entradas "Ninguna" en el diccionario y las entradas faltantes de la misma manera, en ese caso la respuesta aceptada parece funcionar bien.
cib
@Ber he editado la pregunta para aclarar. Podrías haberlo hecho también.
törzsmókus

Respuestas:

814

Puedes usar dict.get()

value = d.get(key)

que volverá Nonesi key is not in d. También puede proporcionar un valor predeterminado diferente que se devolverá en lugar de None:

value = d.get(key, "empty")
Tim Pietzcker
fuente
47
Tenga en cuenta que la segunda variante con una reserva predeterminada seguirá regresando Nonesi la clave está asignada explícitamente Noneen el dict. Si eso no es lo que quieres, puedes usar algo como d.get(key) or "empty".
cib
15
@cib: Buen punto, pero la solución tiene un problema similar - si la llave está asignada a ningún valor "Falsy" (como [], "", False, 0.0o, de hecho None), entonces su solución sería volver siempre 0. Si espera Nones como valores, tendrá que hacer la if key in d:verificación explícitamente.
Tim Pietzcker
1
@cib aplaude por eso, no pude resolver lo que estaba haciendo mal aquí.
wobbily_col
@TimPietzcker: ¿puede explicar su respuesta? d.get (clave) o "vacío" en caso de que la clave se asigne a cualquier valor 'falso' está "vacío" si no me equivoco.
MiloMinderbinder
@MiloMinderbinder: "empty"se devuelve si keyno es una clave válida d. No tiene nada que ver con el valor keyasignado.
Tim Pietzcker
63

Extrañar más. Está integrado en el lenguaje.

    >>> ayuda (dict)

    Ayuda en clase dict en módulos integrados:

    clase dict (objeto)
     El | dict () -> nuevo diccionario vacío
     El | dict (mapeo) -> nuevo diccionario inicializado de un objeto de mapeo
     El | (clave, valor) pares
    ...
     El |  
     El | obtener(...)
     El | D.get (k [, d]) -> D [k] si k en D, de lo contrario d. d por defecto es Ninguno.
     El |  
    ...
John La Rooy
fuente
22

Utilizar dict.get

Devuelve el valor de la clave si la clave está en el diccionario; de lo contrario, es el valor predeterminado. Si no se proporciona el valor predeterminado, el valor predeterminado es Ninguno, de modo que este método nunca genere un KeyError.

Daenyth
fuente
19

Debes usar el get()método de la dictclase

d = {}
r = d.get('missing_key', None)

Esto resultará en r == None. Si la clave no se encuentra en el diccionario, la función get devuelve el segundo argumento.

dusktreader
fuente
19
No tiene que pasar Noneexplícitamente. Es el predeterminado.
Björn Pollex
18

Si desea una solución más transparente, puede subclasificar dictpara obtener este comportamiento:

class NoneDict(dict):
    def __getitem__(self, key):
        return dict.get(self, key)

>>> foo = NoneDict([(1,"asdf"), (2,"qwerty")])
>>> foo[1]
'asdf'
>>> foo[2]
'qwerty'
>>> foo[3] is None
True
Björn Pollex
fuente
2
@marineau: Como mencioné en un comentario a otra respuesta, el problema defaultdictes que crecerá cada vez que se solicite un elemento que aún no está allí. Esto no siempre es deseable.
Björn Pollex
@ BjörnPollex Este es, con mucho, el elegante, ¿Alguna pista sobre cómo extender esto para apoyar cualquier profundidad? Me refiero a hacer foo['bar']['test']['sss']que regrese en Nonelugar de una excepción, después de una profundidad, comienza a dar en TypeErrorlugar deKeyError
nehem
@itsneo. Podrías construir toda la estructura de NoneDicts. Esto ayudaría en caso de KeyErrorque ocurriera en el objeto más interno. De lo contrario, el problema es que una vez que devuelve un Noneobjeto ya no puede suscribirse. Un truco feo sería devolver otro objeto que pruebe None. Sin embargo, tenga en cuenta que esto podría provocar errores horribles.
magu_
@ BjörnPollex ¿Se puede cambiar return dict.get(self, key)a return super().get(key)? Entonces, si decido usar OrderedDict en lugar de dict, por ejemplo, no tengo que preocuparme por cambiar varias líneas de código.
Madera el
@Wood ¡Sí, eso sería mucho mejor!
Björn Pollex
12

Usualmente uso un defaultdict para situaciones como esta. Proporciona un método de fábrica que no toma argumentos y crea un valor cuando ve una nueva clave. Es más útil cuando desea devolver algo como una lista vacía en las nuevas claves ( vea los ejemplos ).

from collections import defaultdict
d = defaultdict(lambda: None)
print d['new_key']  # prints 'None'
trabajo
fuente
19
El problema con el defaultdictes que seguirá creciendo cada vez que se solicite un elemento no existente.
Björn Pollex
8

Podrías usar un dict el get()método de objeto , como ya lo han sugerido otros. Alternativamente, dependiendo de exactamente lo que esté haciendo, podría usar una try/exceptsuite como esta:

try:
   <to do something with d[key]>
except KeyError:
   <deal with it not being there>

Lo cual se considera un enfoque muy "pitónico" para manejar el caso.

Martineau
fuente
7

Una solución de una línea sería:

item['key'] if 'key' in item else None

Esto es útil al intentar agregar valores de diccionario a una nueva lista y desea proporcionar un valor predeterminado:

p.ej.

row = [item['key'] if 'key' in item else 'default_value']
imapotatoe123
fuente
5

Como otros han dicho anteriormente, puede usar get ().

Pero para buscar una clave, también puede hacer:

d = {}
if 'keyname' in d:

    # d['keyname'] exists
    pass

else:

    # d['keyname'] does not exist
    pass
Marek P
fuente
Ahora veo que ya sabes cómo hacer esto. Iba a eliminar mi publicación, pero la dejaré como referencia para otros.
Marek P
44
Este enfoque generalmente requiere que la clave se busque dos veces cuando está allí, lo que probablemente sea la razón del getmétodo.
Martineau
0

Me sorprendió lo que era posible en python2 vs python3. Lo responderé en función de lo que terminé haciendo para python3. Mi objetivo era simple: verificar si una respuesta json en formato de diccionario daba un error o no. Mi diccionario se llama "token" y mi clave que estoy buscando es "error". Estoy buscando "error" clave y si no estaba allí configurándolo en el valor Ninguno, entonces la comprobación es el valor Ninguno, si es así, proceda con mi código. Una instrucción else manejaría si tengo la clave "error".

if ((token.get('error', None)) is None):
    do something
FastGTR
fuente
-2

Si puede hacerlo False, entonces, también está la función integrada hasattr :

e=dict()
hasattr(e, 'message'):
>>> False
Evhz
fuente