Perché dict.get (chiave) invece di dict [chiave]?


651

Oggi mi sono imbattuto nel dictmetodo getche, data una chiave nel dizionario, restituisce il valore associato.

A quale scopo è utile questa funzione? Se volessi trovare un valore associato a una chiave in un dizionario, posso semplicemente farlo dict[key]e restituisce la stessa cosa:

dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")

1
dictionary["foo"]e dictionary.get("foo")comportarsi diversamente, però.
Niklas B.

34
dictionary.get("Age") è lo stesso della scrittura, dictionary["Age"] or None quindi gestisce implicitamente l'eccezione KeyError
yosemite_k

5
@yosemite_k Potrei mancare un po 'di contesto qui, ma dictionary['non-existent key'] or Nonedovrei e sollevo ancora una KeyErrorper me (fino alla v3.6). Puoi spiegare cosa intendi?
nivk

Il dizionario @nivk ['chiave inesistente'] genera un errore e tale errore deve essere gestito in modo esplicito. se invece si utilizza dizionari.get () (che funziona letteralmente come dizionario ['chiave inesistente'] o Nessuno) tale eccezione viene gestita implicitamente.
yosemite_k,

Risposte:


993

Ti consente di fornire un valore predefinito se manca la chiave:

dictionary.get("bogus", default_value)

ritorna default_value(qualunque cosa tu scelga di essere), mentre

dictionary["bogus"]

alzerebbe a KeyError.

Se omesso, default_valueè Nonetale che

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

ritorna Noneproprio come

dictionary.get("bogus", None)

voluto.


1
Sarebbe lo stesso di dictionary.get("bogus") or my_default? Ho visto persone usarlo in alcuni casi e mi chiedevo se ci fosse qualche vantaggio nell'usarne uno invece dell'altro (oltre alla leggibilità)
Algorithmatic

15
@MustafaS: Se "bogus"è una chiave dictionarye dictionary.get("bogus")restituisce un valore che restituisce Falso in un contesto booleano (ovvero un valore Falsey), come 0 o una stringa vuota '', allora dictionary.get("bogus") or my_defaultvaluterebbe my_defaultmentre dictionary.get("bogus", my_default)restituirebbe il valore Falsey. Quindi no, dictionary.get("bogus") or my_defaultnon è equivalente a dictionary.get("bogus", my_default). Quale usare dipende dal comportamento che desideri.
unutbu,

3
@MustafaS: ad esempio, supponiamo x = {'a':0}. Quindi x.get('a', 'foo')ritorna 0ma x.get('a') or 'foo'ritorna 'foo'.
unutbu,

3
Un possibile avvertimento quando si utilizza dictionary.get('key'): può essere fonte di confusione se i valori nel dizionario lo sono None. Senza specificare il valore restituito (secondo argomento facoltativo) non è possibile verificare se la chiave non esiste o se il suo valore è None. In questo caso specifico prenderei in considerazione l'utilizzo try-except-KeyError.
Aart Goossens,

1
Vale la pena notare che l'espressione per specificare il valore predefinito viene valutata nella chiamata "get" e quindi valutata ad ogni accesso. Un'alternativa classica (che utilizza un gestore KeyError o un predicato) è valutare il valore predefinito solo se manca la chiave. Ciò consente di creare una chiusura / lambda una volta e valutarla su qualsiasi chiave mancante.
Tom Stambaugh,

142

Qual è il dict.get()metodo?

Come già accennato, il getmetodo contiene un parametro aggiuntivo che indica il valore mancante. Dalla documentazione

get(key[, default])

Restituisce il valore per chiave se chiave è nel dizionario, altrimenti impostazione predefinita. Se non viene fornito il valore predefinito, il valore predefinito è Nessuno, quindi questo metodo non genera mai a KeyError.

Un esempio può essere

>>> 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

Ci sono miglioramenti di velocità ovunque?

Come menzionato qui ,

Sembra che tutti e tre gli approcci mostrino ora prestazioni simili (entro circa il 10% l'una dall'altra), più o meno indipendenti dalle proprietà dell'elenco di parole.

In precedenza getera considerevolmente più lento, tuttavia ora la velocità è quasi comparabile con l'ulteriore vantaggio di restituire il valore predefinito. Ma per cancellare tutte le nostre domande, possiamo testare su un elenco abbastanza grande (Nota che il test include solo la ricerca di tutte le chiavi valide)

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

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

Ora cronometrando queste due funzioni usando 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

Come possiamo vedere, la ricerca è più veloce di get in quanto non esiste una ricerca di funzioni. Questo può essere visto attraversodis

>>> 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  

Dove sarà utile?

Sarà utile ogni volta che desideri fornire un valore predefinito ogni volta che cerchi un dizionario. Questo riduce

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

Su una sola riga, val = dic.get(key,def_val)

Dove NON sarà utile?

Ogni volta che si desidera restituire una KeyErrordichiarazione che la chiave particolare non è disponibile. Restituire un valore predefinito comporta anche il rischio che anche un determinato valore predefinito possa essere una chiave!

È possibile avere getfunzionalità simili in dict['key']?

Sì! Dobbiamo implementare la __missing__sottoclasse in in dict.

Un programma di esempio può essere

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

Una piccola dimostrazione può essere

>>> my_d = MyDict({1:2,2:3})
>>> my_d[1]
2
>>> my_d[3]
>>> repr(my_d[3])
'None'

32
Il gold standard di StackOverflow risponde!
Apollo Data


1
Un altro buon test sarebbe if k in dict and dict[k]:vs if dict.get(k):. Questo copre la situazione in cui abbiamo bisogno di controllare se la chiave esiste, e se 'sì' - che valore ?, qualcosa come: dict = {1: '', 2: 'some value'}.
TitanFighter

7
Ricorda che il valore predefinito viene valutato indipendentemente dal valore nel dizionario, quindi invece di dictionary.get(value, long_function())prendere in considerazione l'usodictionary.get(value) or long_function()
Kresimir

Ah @Kresimir, vero. Ho ricevuto quella domanda in una delle interviste che ho affrontato (non lo sapevo quando avevo originariamente pubblicato questa risposta). Grazie per avermelo ricordato.
Bhargav Rao

32

getaccetta un secondo valore opzionale. Se la chiave specificata non esiste nel dizionario, questo valore verrà restituito.

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

Se non si specifica il secondo parametro, Noneverrà restituito.

Se si utilizza l'indicizzazione come in dictionary['Year'], le chiavi inesistenti aumenteranno KeyError.


19

Darò un esempio pratico nel raschiare dati web usando Python, molte volte otterrai chiavi senza valori, in quei casi otterrai errori se usi il dizionario ['chiave'], mentre dizionario.get ('chiave ',' return_otherwise ') non ha problemi.

Allo stesso modo, userei '' .join (list) anziché list [0] se provi a catturare un singolo valore da un elenco.

spero che sia d'aiuto.

[Modifica] Ecco un esempio pratico:

Supponiamo che tu stia chiamando un'API che restituisce un file JOSN che devi analizzare. Il primo JSON è simile al seguente:

{"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"}}

Il secondo JOSN è così:

{"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"}}

Si noti che nel secondo JSON manca la chiave "submitdate_ts", che è abbastanza normale in qualsiasi struttura di dati.

Quindi quando provi ad accedere al valore di quella chiave in un ciclo, puoi chiamarlo con il seguente:

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

Potresti, ma ti darà un errore di traceback per la seconda riga JSON, perché la chiave semplicemente non esiste.

Il modo appropriato di codificare questo potrebbe essere il seguente:

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

{'x': Nessuno} è lì per evitare che il secondo livello ottenga un errore. Naturalmente puoi aggiungere più tolleranza agli errori nel codice se stai eseguendo lo scraping. Come prima specifica una condizione if


2
Una buona risposta, pubblicata prima di qualsiasi altra, che sarebbe stata votata di più, e probabilmente accettata, se avessi pubblicato alcuni esempi di codice (+1 da me, però)
Mawg dice di ripristinare Monica

2
@Mawg Di recente ho avuto un progetto di raschiatura per la mia ricerca. Stava chiamando un'API e analizzando sostanzialmente i file JSON. Ho dovuto farlo fare alla mia RA. Uno dei problemi chiave che aveva era chiamare la chiave direttamente, quando in realtà mancano molte chiavi. Pubblicherò un esempio nel testo sopra.
Kevin

grazie per aver affrontato l'aspetto multidimensionale di questo! Sembra che tu possa anche solo fare {} invece di {'x': None}
bluppfisk il

17

Lo scopo è che puoi dare un valore predefinito se la chiave non viene trovata, il che è molto utile

dictionary.get("Name",'harry')

8

A quale scopo è utile questa funzione?

Un utilizzo particolare è il conteggio con un dizionario. Supponiamo che tu voglia contare il numero di occorrenze di ciascun elemento in un dato elenco. Il modo comune per farlo è creare un dizionario in cui le chiavi sono elementi e i valori sono il numero di occorrenze.

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

Utilizzando il .get()metodo, puoi rendere questo codice più compatto e chiaro:

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

7

Un gotcha da tenere presente quando si utilizza .get():

Se il dizionario contiene la chiave utilizzata nella chiamata .get()e il suo valore è None, il .get()metodo restituirà Noneanche se viene fornito un valore predefinito.

Ad esempio, i seguenti ritorni None, non 'alt_value'come previsto:

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

.get()Il secondo valore viene restituito solo se la chiave fornita NON è nel dizionario, non se il valore restituito di quella chiamata è None.


1
Questo mi ha procurato: \ Un modo per risolverlo è avere d.get('key') or 'alt_value'se sai che potrebbe essereNone
Daniel Holmes,

4

Perché dict.get (chiave) invece di dict [chiave]?

0. Riepilogo

Rispetto a dict[key], dict.getfornisce un valore di fallback quando si cerca una chiave.

1. Definizione

get (key [, default]) 4. Tipi predefiniti - Documentazione di Python 3.6.4rc1

Restituisce il valore per chiave se chiave è nel dizionario, altrimenti impostazione predefinita. Se non viene fornito il valore predefinito, il valore predefinito è Nessuno, quindi questo metodo non genera mai un 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. Problema che risolve.

Se senza default value, devi scrivere codici ingombranti per gestire una simile eccezione.

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'

Come soluzione conveniente, dict.getintroduce un valore predefinito facoltativo evitando codici sopra involontariamente.

3. Conclusione

dict.get ha un'opzione di valore predefinita aggiuntiva per gestire l'eccezione se la chiave è assente dal dizionario


0

Una differenza, che può essere un vantaggio, è che se stiamo cercando una chiave che non esiste otterremo Nessuno, non come quando usiamo la notazione tra parentesi, nel qual caso verrà generato un errore:

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

L'ultima cosa interessante del metodo get è che riceve un argomento opzionale aggiuntivo per un valore predefinito, vale a dire se proviamo a ottenere il valore del punteggio di uno studente, ma lo studente non ha una chiave di punteggio che possiamo ottenere uno 0 invece.

Quindi invece di fare questo (o qualcosa di simile):

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

Possiamo farlo:

score = dictionary.get("score", 0)
# score = 0

-1

In base all'utilizzo dovrebbe utilizzare questo getmetodo.

Esempio 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]: ''

Esempio 2

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'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.