J'ai un dictionnaire Python comme mydict = {'nom':'abc','ville':'xyz','pays','def'}
.
Comment puis-je vérifier si une clé se trouve dans le dictionnaire ou pas? Je connais déjà ces méthodes :
if mydict.has_key('nom'):
if 'nom' in mydict:
J'ai un dictionnaire Python comme mydict = {'nom':'abc','ville':'xyz','pays','def'}
.
Comment puis-je vérifier si une clé se trouve dans le dictionnaire ou pas? Je connais déjà ces méthodes :
if mydict.has_key('nom'):
if 'nom' in mydict:
if 'name' in mydict:
est la version préférée et pythonique. L'utilisation de has_key()
est découragée, et cette méthode a été supprimée en Python 3.
Aussi, "nom" dans dict
fonctionnera avec n'importe quel itérable et pas seulement avec des dictionnaires.
@PulpFiction: La méthode dict.get(key)
peut être utile lorsque vous (1) ne voulez pas obtenir une erreur de type KeyError
si key
n'est pas dans le dictionnaire (2) voulez utiliser une valeur par défaut s'il n'y a pas de key
(dict.get(key, default)
). Le point #2 peut également être réalisé en utilisant defaultdict
.
Sur le même thème que la réponse de martineau, la meilleure solution est souvent de ne pas vérifier. Par exemple, le code
if x in d:
foo = d[x]
else:
foo = bar
est normalement écrit
foo = d.get(x, bar)
ce qui est plus court et exprime plus directement ce que vous voulez dire.
Un autre cas courant est quelque chose comme
if x not in d:
d[x] = []
d[x].append(foo)
qui peut être réécrit
d.setdefault(x, []).append(foo)
ou réécrit encore mieux en utilisant un collections.defaultdict(list)
pour d
et en écrivant
d[x].append(foo)
En termes de bytecode, in
sauve un LOAD_ATTR
et remplace un CALL_FUNCTION
par un COMPARE_OP
.
>>> dis.dis(indict)
2 0 LOAD_GLOBAL 0 (name)
3 LOAD_GLOBAL 1 (d)
6 COMPARE_OP 6 (in)
9 POP_TOP
>>> dis.dis(haskey)
2 0 LOAD_GLOBAL 0 (d)
3 LOAD_ATTR 1 (haskey)
6 LOAD_GLOBAL 2 (name)
9 CALL_FUNCTION 1
12 POP_TOP
Je pense que in
est beaucoup plus lisible et est à privilégier dans tous les cas que je peux penser.
En termes de performances, le chronométrage reflète le bytecode
$ python -mtimeit -s'd = dict((i, i) for i in range(10000))' "'foo' in d"
10000000 boucles, meilleure de 3: 0.11 usec par boucle
$ python -mtimeit -s'd = dict((i, i) for i in range(10000))' "d.has_key('foo')"
1000000 boucles, meilleure de 3: 0.205 usec par boucle
in
est presque deux fois plus rapide.
Toutes les mesures de vitesse sont bien sûr spécifiques au problème, généralement sans importance, dépendantes de l'implémentation, potentiellement dépendantes de la version, et moins importantes que les problèmes de désuétude et de style.
@Mike Graham, tu as en grande partie raison. J'ai inclus le pire des cas là-dedans parce que, à mon avis, c'est là que tu veux vraiment savoir. De plus, je pense que ton attitude est (bien que tout à fait correcte), légèrement plus appropriée pour un langage comme le C où c'est rapide de toute façon, sauf si tu fais vraiment une erreur. En Python, il vaut la peine de le faire correctement dans une plus grande mesure. De plus, les développeurs principaux ont un moyen d'accorder "la seule bonne façon" de faire quelque chose pour que, encore une fois, les performances soient un bon indicateur d'un bon style dans une plus grande mesure que d'habitude dans un langage.
Ma réponse est "aucun des deux".
Je crois que la manière la plus "pythonique" de faire les choses est de NE PAS vérifier au préalable si la clé est dans un dictionnaire et plutôt écrire du code qui suppose qu'elle est là et attraper les KeyErrors qui sont levées parce que ce n'était pas le cas.
Cela se fait généralement en encapsulant le code dans une clause try...except
et est un idiome bien connu habituellement exprimé comme "Il vaut mieux demander le pardon que la permission" ou avec l'acronyme EAFP, ce qui signifie essentiellement qu'il vaut mieux essayer quelque chose et attraper les erreurs plutôt que de vérifier que tout est OK avant de faire quoi que ce soit. Pourquoi valider ce qui n'a pas besoin d'être validé lorsque vous pouvez gérer les exceptions de manière gracieuse au lieu d'essayer de les éviter ? Parce que c'est souvent plus lisible et que le code tend à être plus rapide si la probabilité que la clé ne soit pas là (ou toute autre condition préalable) est faible.
Bien sûr, cela n'est pas approprié dans toutes les situations et tout le monde n'est pas d'accord avec cette philosophie, donc vous devrez décider par vous-même au cas par cas. Sans surprise, l'opposé de ceci est appelé LBYL pour "Look Before You Leap".
Par exemple, considérez :
if 'name' in dct:
value = dct['name'] * 3
else:
logerror('"%s" non trouvé dans le dictionnaire, en utilisant par défaut' % name)
value = 42
vs
try:
value = dct['name'] * 3
except KeyError:
logerror('"%s" non trouvé dans le dictionnaire, en utilisant par défaut' % name)
value = 42
Quoique dans ce cas, ce soit presque exactement la même quantité de code, le second ne perd pas de temps à vérifier d'abord et est probablement légèrement plus rapide à cause de cela (bloc try...except n'est pas totalement gratuit cependant, donc cela ne fait probablement pas une grande différence ici).
En général, tester à l'avance peut souvent être beaucoup plus impliqué et les gains réalisés en ne le faisant pas peuvent être significatifs. Cela dit, if 'name' in dict:
est meilleur pour les raisons énoncées dans les autres réponses.
Si le sujet vous intéresse, ce message intitulé "EAFP vs LBYL (was Re: A little disappointed so far)" des archives de la liste de diffusion Python explique probablement mieux la différence entre les deux approches que je ne l'ai fait ici. Il y a également une bonne discussion sur les deux approches dans le livre Python in a Nutshell, 2ème édition par Alex Martelli dans le chapitre 6 sur les Exceptions intitulé Stratégies de vérification des erreurs. (Je vois qu'il y a maintenant une nouvelle 3ème édition, publiée en 2017, qui couvre à la fois Python 2.7 et 3.x).
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
5 votes
Soit dit en passant,
dict
est le nom d'un type intégré de Python, il est donc préférable d'éviter de l'utiliser comme nom de variable dans vos scripts (bien que strictement parlant, c'est légal de le faire).4 votes
Les documents sont assez clairs, non?
1 votes
En Python 3, les objets
dict
n'ont plus de méthodehas_key()
, donc en termes de portabilité de version, l'opérateurin
est meilleur.