Renvoyer aucun si la clé du dictionnaire n'est pas disponible

490

J'ai besoin d'un moyen pour obtenir une valeur de dictionnaire si sa clé existe, ou simplement retourner None, sinon.

Cependant, Python lève une KeyErrorexception si vous recherchez une clé qui n'existe pas. Je sais que je peux vérifier la clé, mais je cherche quelque chose de plus explicite. Existe-t-il un moyen de simplement revenir Nonesi la clé n'existe pas?

Spyros
la source
74
Utilisez simplement .get(key)au lieu de[key]
Gabe
12
Un dict déclenche une exception KeyError. Il ne "renvoie pas key_error".
Ber
3
Accéder à la clé et intercepter l'exception est parfaitement correct en Python. C'est même un modèle de conception bien connu et souvent utilisé. Si vous renvoyez None à la place, il devient impossible de stocker None comme valeur, ce qui peut être pertinent dans certains cas.
Ber
1
Parfois, vous voulez traiter les entrées "Aucune" dans le dictionnaire et les entrées manquantes de la même manière, dans ce cas, la réponse acceptée semble faire l'affaire.
cib
@Ber J'ai édité la question pour clarifier. Vous auriez pu le faire également.
törzsmókus

Réponses:

814

Vous pouvez utiliser dict.get()

value = d.get(key)

qui reviendra Nonesi key is not in d. Vous pouvez également fournir une valeur par défaut différente qui sera retournée au lieu de None:

value = d.get(key, "empty")
Tim Pietzcker
la source
47
Notez que la deuxième variante avec un repli par défaut sera toujours de retour None si la clé est explicitement mappée Nonedans le dict. Si ce n'est pas ce que vous voulez, vous pouvez utiliser quelque chose comme d.get(key) or "empty".
cib
15
@cib: Bon point, mais la solution a un problème similaire - si la clé est associée à une valeur « falsy » (comme [], "", False, 0.0ou bien None), alors votre solution retournerait toujours 0. Si vous attendez Nones comme valeurs, vous devrez faire la if key in d:vérification explicitement.
Tim Pietzcker
1
@cib applaudit pour cela, je n'ai pas pu comprendre ce que je faisais mal ici.
wobbily_col
@TimPietzcker - pouvez-vous s'il vous plaît expliquer votre réponse? d.get (clé) ou "vide" en cas de mappage de clé à des valeurs "fausses" est "vide" si je ne me trompe pas.
MiloMinderbinder
@MiloMinderbinder: "empty"est retourné s'il keyne s'agit pas d'une clé valide d. Cela n'a rien à voir avec la valeur keymappée.
Tim Pietzcker
63

Je ne me demande plus. C'est intégré à la langue.

    >>> aide (dict)

    Aide sur la classe dict dans les modules intégrés:

    classe dict (objet)
     | dict () -> nouveau dictionnaire vide
     | dict (mapping) -> nouveau dictionnaire initialisé à partir d'un objet de mapping
     | (clé, valeur) paires
    ...
     |  
     | avoir(...)
     | D.get (k [, d]) -> D [k] si k dans D, sinon d. d est réglé par défaut sur Aucun.
     |  
    ...
John La Rooy
la source
22

Utilisation dict.get

Renvoie la valeur de key si key est dans le dictionnaire, sinon par défaut. Si la valeur par défaut n'est pas indiquée, elle est définie par défaut sur None, de sorte que cette méthode ne déclenche jamais une erreur KeyError.

Daenyth
la source
19

Vous devez utiliser la get()méthode de la dictclasse

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

Cela se traduira par r == None. Si la clé n'est pas trouvée dans le dictionnaire, la fonction get renvoie le deuxième argument.

crépuscule
la source
19
Vous n'avez pas besoin de passer Noneexplicitement. C'est la valeur par défaut.
Björn Pollex
18

Si vous voulez une solution plus transparente, vous pouvez sous-classer dictpour obtenir ce comportement:

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
la source
2
@marineau: Comme je l'ai mentionné dans un commentaire à une autre réponse, le problème avec le defaultdictest qu'il augmentera à chaque fois qu'un élément qui n'est pas encore là est demandé. Ce n'est pas toujours souhaitable.
Björn Pollex
@ BjörnPollex C'est de loin l'élégant, un indice sur la façon de l'étendre pour supporter n'importe quelle profondeur? Je veux dire faire foo['bar']['test']['sss']revenir Noneau lieu d'exception, après une profondeur, il commence à donner TypeErrorau lieu deKeyError
nehem
@itsneo. Vous pouvez construire la structure entière de NoneDicts. Cela aiderait au cas où KeyErrorcela se produirait dans l'objet le plus intérieur. Sinon, le problème est qu'une fois que vous retournez un Noneobjet, vous ne pouvez plus y souscrire. Un hack laid serait de retourner un autre objet qui teste comme None. Attention cependant, cela pourrait conduire à des bugs horribles.
magu_
@ BjörnPollex Est-il correct de passer return dict.get(self, key)à return super().get(key)? Ensuite, si je décide d'utiliser OrderedDict au lieu de dict, par exemple, je n'ai pas à me soucier de changer plusieurs lignes de code.
Wood
@Wood Oui, ce serait bien mieux!
Björn Pollex
12

J'utilise généralement un défaut par défaut pour des situations comme celle-ci. Vous fournissez une méthode d'usine qui ne prend aucun argument et crée une valeur lorsqu'il voit une nouvelle clé. C'est plus utile lorsque vous souhaitez renvoyer quelque chose comme une liste vide sur de nouvelles clés ( voir les exemples ).

from collections import defaultdict
d = defaultdict(lambda: None)
print d['new_key']  # prints 'None'
emploi
la source
19
Le problème avec le defaultdictest qu'il continuera de croître chaque fois qu'un élément inexistant est demandé.
Björn Pollex
8

Vous pouvez utiliser dictla get()méthode d' un objet , comme d'autres l'ont déjà suggéré. Alternativement, selon exactement ce que vous faites, vous pourrez peut-être utiliser une try/exceptsuite comme celle-ci:

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

Ce qui est considéré comme une approche très "Pythonique" pour gérer le cas.

martineau
la source
7

Une solution sur une seule ligne serait:

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

Ceci est utile lorsque vous essayez d'ajouter des valeurs de dictionnaire à une nouvelle liste et que vous souhaitez fournir une valeur par défaut:

par exemple.

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

Comme d'autres l'ont dit plus haut, vous pouvez utiliser get ().

Mais pour vérifier une clé, vous pouvez également faire:

d = {}
if 'keyname' in d:

    # d['keyname'] exists
    pass

else:

    # d['keyname'] does not exist
    pass
Marek P
la source
Je vois maintenant que vous savez déjà comment procéder. J'allais supprimer mon message, mais je vais le laisser pour référence à d'autres.
Marek P
4
Cette approche nécessite généralement que la clé soit recherchée deux fois lorsqu'elle est là, ce qui est probablement la raison de la getméthode.
martineau
0

J'ai été abasourdi par ce qui était possible en python2 vs python3. Je vais y répondre en fonction de ce que j'ai fini par faire pour python3. Mon objectif était simple: vérifier si une réponse json au format dictionnaire donnait une erreur ou non. Mon dictionnaire s'appelle "token" et ma clé que je recherche est "error". Je recherche la clé "erreur" et si elle n'était pas là, la définissant sur la valeur None, alors je vérifie que la valeur est None, si c'est le cas, continuez avec mon code. Une instruction else serait gérée si j'ai la clé "erreur".

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

Si vous pouvez le faire avec False, alors, il y a aussi la fonction intégrée hasattr :

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