Pourquoi dict.get (clé) au lieu de dict [clé]?

650

Aujourd'hui, je suis tombé sur la dictméthode getqui, étant donné une clé dans le dictionnaire, renvoie la valeur associée.

Dans quel but cette fonction est-elle utile? Si je voulais trouver une valeur associée à une clé dans un dictionnaire, je peux simplement le faire dict[key], et cela renvoie la même chose:

dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")
stensootla
la source
1
dictionary["foo"]et dictionary.get("foo")se comportent différemment, cependant.
Niklas B.
34
dictionary.get("Age") est identique à l'écriture, dictionary["Age"] or None donc il gère implicitement l'exception KeyError
yosemite_k
5
@yosemite_k Il se peut que je manque un peu de contexte ici, mais je dois et je dictionary['non-existent key'] or Nonesoulève toujours un KeyErrorpour moi (jusqu'à la v3.6). Pouvez-vous expliquer ce que vous voulez dire?
nivk
Le dictionnaire @nivk ['clé inexistante'] génère une erreur, et cette erreur doit être explicitement gérée. si à la place vous utilisez dictionary.get () (qui fonctionne littéralement comme dictionnaire ['clé inexistante'] ou None) cette exception est implicitement gérée.
yosemite_k

Réponses:

995

Il vous permet de fournir une valeur par défaut si la clé est manquante:

dictionary.get("bogus", default_value)

retourne default_value(quel que soit votre choix), tandis que

dictionary["bogus"]

soulèverait un KeyError.

Si omis, default_valueest Nonetel que

dictionary.get("bogus")  # <-- No default specified -- defaults to None

renvoie Nonecomme

dictionary.get("bogus", None)

aurait.

unutbu
la source
1
Serait-ce la même chose que dictionary.get("bogus") or my_default? J'ai vu des gens l'utiliser dans certains cas et je me demandais s'il y avait un avantage à utiliser l'un au lieu de l'autre (autre que la lisibilité)
Algorithmatic
15
@MustafaS: si "bogus"est une clé dictionaryet dictionary.get("bogus")renvoie une valeur qui est évaluée à False dans un contexte booléen (c'est-à-dire une valeur Falsey), telle que 0 ou une chaîne vide,, ''alors dictionary.get("bogus") or my_defaultévaluerait my_defaultalors dictionary.get("bogus", my_default)que retournerait la valeur Falsey. Donc non, ce dictionary.get("bogus") or my_defaultn'est pas équivalent à dictionary.get("bogus", my_default). Lequel utiliser dépend du comportement que vous désirez.
unutbu
3
@MustafaS: Par exemple, supposons x = {'a':0}. x.get('a', 'foo')Retourne ensuite 0mais x.get('a') or 'foo'revient 'foo'.
unutbu
3
Une mise en garde possible lors de l'utilisation dictionary.get('key'): Cela peut être déroutant si les valeurs du dictionnaire le sont None. Sans spécifier la valeur de retour (deuxième argument facultatif), il n'y a aucun moyen de vérifier si la clé n'existait pas ou si sa valeur est None. Dans ce cas précis, j'envisagerais d'utiliser try-except-KeyError.
Aart Goossens
1
Il convient de noter que l'expression pour spécifier la valeur par défaut est évaluée dans l'appel "get" et est donc évaluée à chaque accès. Une alternative classique (en utilisant un gestionnaire KeyError ou un prédicat) consiste à évaluer la valeur par défaut uniquement si la clé est manquante. Cela permet à une fermeture / lambda d'être créée une fois et évaluée sur toute clé manquante.
Tom Stambaugh le
143

Quelle est la dict.get()méthode?

Comme déjà mentionné, la getméthode contient un paramètre supplémentaire qui indique la valeur manquante. De la documentation

get(key[, default])

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 a KeyError.

Un exemple peut être

>>> d = {1:2,2:3}
>>> d[1]
2
>>> d.get(1)
2
>>> d.get(3)
>>> repr(d.get(3))
'None'
>>> d.get(3,1)
1

Y a-t-il des améliorations de vitesse quelque part?

Comme mentionné ici ,

Il semble que les trois approches présentent désormais des performances similaires (à environ 10% l'une de l'autre), plus ou moins indépendantes des propriétés de la liste de mots.

Plus tôt getétait considérablement plus lent, mais maintenant la vitesse est presque comparable avec l'avantage supplémentaire de retourner la valeur par défaut. Mais pour effacer toutes nos requêtes, nous pouvons tester sur une liste assez longue (Notez que le test inclut la recherche de toutes les clés valides uniquement)

def getway(d):
    for i in range(100):
        s = d.get(i)

def lookup(d):
    for i in range(100):
        s = d[i]

Maintenant, chronométrez ces deux fonctions en utilisant timeit

>>> import timeit
>>> print(timeit.timeit("getway({i:i for i in range(100)})","from __main__ import getway"))
20.2124660015
>>> print(timeit.timeit("lookup({i:i for i in range(100)})","from __main__ import lookup"))
16.16223979

Comme nous pouvons le voir, la recherche est plus rapide que le get car il n'y a pas de recherche de fonction. Cela peut être vu à traversdis

>>> def lookup(d,val):
...     return d[val]
... 
>>> def getway(d,val):
...     return d.get(val)
... 
>>> dis.dis(getway)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_ATTR                0 (get)
              6 LOAD_FAST                1 (val)
              9 CALL_FUNCTION            1
             12 RETURN_VALUE        
>>> dis.dis(lookup)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_FAST                1 (val)
              6 BINARY_SUBSCR       
              7 RETURN_VALUE  

Où cela sera-t-il utile?

Il sera utile chaque fois que vous souhaitez fournir une valeur par défaut chaque fois que vous recherchez un dictionnaire. Cela réduit

 if key in dic:
      val = dic[key]
 else:
      val = def_val

Sur une seule ligne, val = dic.get(key,def_val)

Où ne sera-t-il PAS utile?

Chaque fois que vous souhaitez retourner un KeyErrorindiquant que la clé particulière n'est pas disponible. Le retour d'une valeur par défaut comporte également le risque qu'une valeur par défaut particulière soit également une clé!

Est-il possible d'avoir une getfonctionnalité similaire dans dict['key']?

Oui! Nous devons implémenter la __missing__sous-classe in a dict.

Un exemple de programme peut être

class MyDict(dict):
    def __missing__(self, key):
        return None

Une petite démonstration peut être

>>> my_d = MyDict({1:2,2:3})
>>> my_d[1]
2
>>> my_d[3]
>>> repr(my_d[3])
'None'
Bhargav Rao
la source
32
L'étalon-or des réponses StackOverflow!
Apollo Data
1
Encore un bon test serait if k in dict and dict[k]:vs if dict.get(k):. Cette garantie couvre la situation où nous devons vérifier si la clé existe, et si « oui » - quelle valeur ?, quelque chose comme: dict = {1: '', 2: 'some value'}.
TitanFighter
7
N'oubliez pas que la valeur par défaut est évaluée quelle que soit la valeur dans le dictionnaire, donc au lieu d' dictionary.get(value, long_function())envisager d'utiliserdictionary.get(value) or long_function()
Kresimir
Ah @Kresimir, c'est vrai. J'ai obtenu cette question dans l'une des interviews que j'ai rencontrées (je ne savais pas à ce sujet lorsque j'avais initialement posté cette réponse). Merci de me l'avoir rappelé.
Bhargav Rao
33

getprend une deuxième valeur facultative. Si la clé spécifiée n'existe pas dans votre dictionnaire, cette valeur sera renvoyée.

dictionary = {"Name": "Harry", "Age": 17}
dictionary.get('Year', 'No available data')
>> 'No available data'

Si vous ne donnez pas le deuxième paramètre, Nonesera retourné.

Si vous utilisez l'indexation comme dans dictionary['Year'], les clés inexistantes augmenteront KeyError.

Ange déchu
la source
20

Je vais vous donner un exemple pratique de grattage de données Web à l'aide de python, la plupart du temps, vous obtiendrez des clés sans valeurs, dans ces cas, vous obtiendrez des erreurs si vous utilisez dictionnaire ['clé'], tandis que dictionnaire.get ('clé ',' return_otherwise ') n'a aucun problème.

De même, j'utiliserais '' .join (list) par opposition à list [0] si vous essayez de capturer une seule valeur d'une liste.

J'espère que cela aide.

[Modifier] Voici un exemple pratique:

Dites, vous appelez une API, qui renvoie un fichier JOSN que vous devez analyser. Le premier JSON ressemble à ceci:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","submitdate_ts":1318794805,"users_id":"2674360","project_id":"1250499"}}

Le deuxième JOSN est comme ceci:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","users_id":"2674360","project_id":"1250499"}}

Notez que le deuxième JSON n'a pas la clé "submitdate_ts", ce qui est assez normal dans n'importe quelle structure de données.

Ainsi, lorsque vous essayez d'accéder à la valeur de cette clé dans une boucle, pouvez-vous l'appeler comme suit:

for item in API_call:
    submitdate_ts = item["bids"]["submitdate_ts"]

Vous pourriez, mais cela vous donnera une erreur de trace pour la deuxième ligne JSON, car la clé n'existe tout simplement pas.

La manière appropriée de coder cela pourrait être la suivante:

for item in API_call:
    submitdate_ts = item.get("bids", {'x': None}).get("submitdate_ts")

{'x': Aucun} est là pour éviter que le deuxième niveau ne reçoive une erreur. Bien sûr, vous pouvez intégrer davantage de tolérance aux pannes dans le code si vous effectuez un grattage. Comme en spécifiant d'abord une condition if

Kevin
la source
2
Une bonne réponse, postée avant les autres, qui aurait été plus votée, et probablement acceptée, si vous aviez posté quelques exemples de code (+1 de moi, cependant)
Mawg dit rétablir Monica
2
@Mawg J'ai récemment eu un projet de grattage pour mes recherches. Il appelait une API et analysait essentiellement les fichiers JSON. J'ai fait faire ma RA. L'un des problèmes clés qu'il avait eu était d'appeler directement la clé, alors que de nombreuses clés manquaient réellement. Je posterai un exemple dans le texte ci-dessus.
kevin
merci d'avoir abordé l'aspect multidimensionnel de cela! On dirait que vous pouvez même faire {} au lieu de {'x': Aucun}
bluppfisk
18

Le but est que vous puissiez donner une valeur par défaut si la clé n'est pas trouvée, ce qui est très utile

dictionary.get("Name",'harry')
hackartist
la source
8

Un piège à connaître lors de l'utilisation .get():

Si le dictionnaire contient la clé utilisée dans l'appel à .get()et que sa valeur est None, la .get()méthode retournera Nonemême si une valeur par défaut est fournie.

Par exemple, les retours suivants None, pas 'alt_value'comme on peut s'y attendre:

d = {'key': None}
d.get('key', 'alt_value')

.get()La deuxième valeur de 'est retournée uniquement si la clé fournie n'est PAS dans le dictionnaire, pas si la valeur de retour de cet appel l'est None.

Colton Hicks
la source
1
Celui-ci m'a eu: \ Une façon de résoudre ce problème est d'avoir d.get('key') or 'alt_value'si vous savez que cela pourrait êtreNone
Daniel Holmes
8

Dans quel but cette fonction est-elle utile?

Une utilisation particulière consiste à compter avec un dictionnaire. Supposons que vous souhaitiez compter le nombre d'occurrences de chaque élément dans une liste donnée. La manière la plus courante de le faire est de créer un dictionnaire où les clés sont des éléments et les valeurs le nombre d'occurrences.

fruits = ['apple', 'banana', 'peach', 'apple', 'pear']
d = {}
for fruit in fruits:
    if fruit not in d:
        d[fruit] = 0
    d[fruit] += 1

En utilisant la .get()méthode, vous pouvez rendre ce code plus compact et plus clair:

for fruit in fruits:
    d[fruit] = d.get(fruit, 0) + 1
jetpack_guy
la source
4

Pourquoi dict.get (clé) au lieu de dict [clé]?

0. Résumé

Par rapport à dict[key], dict.getfournit une valeur de secours lors de la recherche d'une clé.

1. Définition

get (clé [, par défaut]) 4. Types intégrés - Documentation Python 3.6.4rc1

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.

d = {"Name": "Harry", "Age": 17}
In [4]: d['gender']
KeyError: 'gender'
In [5]: d.get('gender', 'Not specified, please add it')
Out[5]: 'Not specified, please add it'

2. Problème qu'il résout.

Si ce n'est pas le cas default value, vous devez écrire des codes lourds pour gérer une telle exception.

def get_harry_info(key):
    try:
        return "{}".format(d[key])
    except KeyError:
        return 'Not specified, please add it'
In [9]: get_harry_info('Name')
Out[9]: 'Harry'
In [10]: get_harry_info('Gender')
Out[10]: 'Not specified, please add it'

En tant que solution pratique, dict.getintroduit une valeur par défaut facultative en évitant les codes involontaires ci-dessus.

3. Conclusion

dict.get a une option de valeur par défaut supplémentaire pour traiter l'exception si la clé est absente du dictionnaire

Calcul
la source
0

Une différence, qui peut être un avantage, est que si nous recherchons une clé qui n'existe pas, nous obtiendrons None, pas comme lorsque nous utilisons la notation des crochets, auquel cas nous obtiendrons une erreur:

print(dictionary.get("address")) # None
print(dictionary["address"]) # throws KeyError: 'address'

La dernière chose intéressante à propos de la méthode get, c'est qu'elle reçoit un argument facultatif supplémentaire pour une valeur par défaut, c'est-à-dire si nous avons essayé d'obtenir la valeur de score d'un étudiant, mais que l'étudiant n'a pas de clé de score que nous pouvons obtenir un 0 à la place.

Donc au lieu de faire ça (ou quelque chose de similaire):

score = None
try:
    score = dictionary["score"]
except KeyError:
    score = 0

Nous pouvons le faire:

score = dictionary.get("score", 0)
# score = 0
אנונימי
la source
-1

Basé sur l'utilisation devrait utiliser cette getméthode.

Exemple 1

In [14]: user_dict = {'type': False}

In [15]: user_dict.get('type', '')

Out[15]: False

In [16]: user_dict.get('type') or ''

Out[16]: ''

Exemple2

In [17]: user_dict = {'type': "lead"}

In [18]: user_dict.get('type') or ''

Out[18]: 'lead'

In [19]: user_dict.get('type', '')

Out[19]: 'lead'
Muthuvel
la source