16. I Dizionari

In questa lezione parleremo di un nuovo tipo di dato di Python: dict, che significa dictionary (in italiano dizionario).


I dizionari di Python

I dizionari sono simili al tipo di dato lista di cui abbiamo già parlato nelle lezioni precedenti, ma a differenza di queste, in cui ad ogni elemento corrisponde un indice progressivo quindi da 0 in su, nei dizionari ad ogni elemento è associata una chiave chiave, che potrà essere usata per accedere al valore dell'elemento.

Siamo noi a scegliere che chiave usare, e possiamo usare qualsiasi tipo di dato eccetto liste e altri dizionari. Per ogni elemento all'interno del dizionario avremo quindi una coppia chiave / valore.

I dizionari di Python vengono definiti utilizzando una coppia di parentesi graffe che contenga al suo interno delle coppie chiave / valore separate da due punti:

>>> mio_dict = {"mia_chiave": "mio_valore", "age": 29, 3.14: "pi greco", "primi": [2, 3, 5, 7]}
>>> type(mio_dict)

# output
<class 'dict'>

Quindi con questa azione abbiamo definito una struttura di dati contenente quattro coppie chiave : valore, associate al nome mio_dizionario. Come per tutte le variabili, possiamo accedere al valore in esse contenuto (nel nostro caso la struttura dati) tramite il nome stesso della variabile.

>>> mio_dict

# output
{"mia_chiave": "mio_valore", "age": 29, 3.14: "pi greco", "primi": [2, 3, 5, 7]}


Dizionari e coppie chiave valore

Come vedete abbiamo utilizzato diversi tipi di valori, stringhe, interi e liste, associati ciascuno ad una chiave univoca. Le chiavi nei dizionari sono proprio il corrispettivo degli indici nelle Liste: usiamo le chiavi per richiamare i valori ad esse associati.

Per ottenere il valore associato alla chiave mia_chiave_uno facciamo in questo modo:

>>> mio_dict["mia_chiave"]
'mio_valore'

Stesso discorso vale per tutti gli altri valori presenti, richiamabili tramite le loro chiavi. Proviamo a richiamare il valore associato alla chiave 3.14:

>>> mio_dict[3.14]
'pi greco'

Per aggiungere un nuovo elemento al nostro dizionario facciamo in questa maniera:

>>> mio_dict["nuova_chiave"] = "nuovo_valore"

>>> mio_dict
{'mia_chiave': 'mio_valore', 'age': 24, 3.14: 'pi greco', 'primi': [2, 3, 5, 7], 'nuova_chiave': 'nuovo_valore'}

Allo stesso modo possiamo sostituire il valore associato ad una chiave già presente nel dizionario:

>>> mio_dict["age"] = 99
>>> mio_dict
{'mia_chiave': 'mio_valore', 'age': 99, 3.14: 'pi greco', 'primi': [2, 3, 5, 7], 'nuova_chiave': 'nuovo_valore'}

Come verificare la presenza di elementi nei dizionari

Per verificare se una chiave è presente o meno all'interno di un dizionario possiamo utilizzare gli operatori in e not in:

>>> "age" in mio_dict
True

>>> "zen" in mio_dict
False

Come rimuovere elementi da un dizionario

Per rimuovere una coppia chiave-valore possiamo utilizzare l'istruzione del:

>>> del mio_dict["mia_chiave"]
>>> mio_dict
{'age': 99, 3.14: 'pi greco', 'primi': [2, 3, 5, 7], 'nuova_chiave': 'nuovo_valore'}


I metodi dei Dizionari di Python

Come per altri tipi di dato, anche il tipo dict dispone di alcuni metodi propri: analizziamo i principali con un nuovo esempio.

Definiamo un nuovo dizionario associato a una variabile ita_eng e inseriamoci i valori tipici di un dizionario Italiano - Inglese

ita_eng = {"ciao": "hello", "arrivederci": "goodbye", "uova": "eggs", "gatto": "cat", "arancia": "orange"}

Esistono tre metodi associati ai dizionari che ci consentono di ottenere in output una lista di tutte le chiavi presenti, o di tutti i valori presenti, o di entrambi allo stesso tempo: keys(), values() ed items().

Il metodo keys()

Keys è traducibile come "chiavi", ed è proprio il metodo che ci consente di ottenere una lista di tutte le chiavi presenti.

Quindi per ottenere una lista di tutte le chiavi presenti nel nostro dizionario ita_eng facciamo:

>>> ita_eng.keys()

# output
dict_keys(['ciao', 'arrivederci', 'uova', 'gatto', 'arancia'])

Metodo values()

Values significa valori, utilizziamo questo metodo per ottenere una lista di tutti i valori presenti:

>>> ita_eng.values()

# output
dict_values(['hello', 'goodbye', 'eggs', 'cat', 'orange'])

Il metodo items()

Infine utilizziamo il metodo items() per ottenere una lista di tutte le coppie chiavi-valore presenti.

>>> ita_eng.items()

# output
dict_items([('ciao', 'hello'), ('arrivederci', 'goodbye'), ('uova', 'eggs'), ('gatto', 'cat'), ('arancia', 'orange')])

Cosa restituiscono questi metodi?

Come possiamo interpretare dall'output, utilizzando questi metodi non ci vengono restituiti dei valori di tipi lista ma bensì, oggetti di tipo dict_keys, dict_values e dict_items.

Se abbiamo bisogno di una lista vera e propria possiamo utilizzare anche qui la nostra cara funzione list():

>>> parole_eng = list(ita_eng.keys())

>>> parole_eng
['ciao', 'arrivederci', 'uova', 'gatto', 'arancia']

Dizionari e cicli for

Possiamo inoltre utilizzare questi metodi in combinazione con un ciclo for.

Ad esempio, per mandare in print tutte le chiavi del dizionario possiamo fare:

for chiave in ita_eng.keys():
    print(chiave)


# output
ciao
arrivederci
uova
gatto
arancia

Il metodo get()

Ma cosa succederebbe qualora provassimo a richiamare un valore associato a una chiave che non esiste nel nostro dizionario? Come è facile ipotizzare otterremmo un errore, e nello specifico un'eccezione del tipo KeyError, che se non gestita causerà il crash del programma.

>>> ita_eng["birra"]

# output
Traceback (most recent call last):
  File "stdin", line 1, in module
KeyError: 'birra'

Parleremo di gestione degli errori più avanti nel corso introducendo delle istruzioni dedicate.

Alcuni/e tra voi a questo punto staranno però pensando: be, abbiamo visto come usare le istruzioni if ed else, perché non usare queste due per evitare il crash del programma? Potremmo in effetti fare qualcosa di questo tipo:

if "birra" in ita_eng.keys():
    print(ita_eng["birra"])
else:
    print("Chiave non trovata!")

# output
Chiave non trovata!

Il metodo funziona ma richiede parecchie righe di codice che dobbiamo scrivere da noi! E ricordate come uno dei concetti più importanti di cui abbiamo discusso sia il riutilizzo del codice?

Fortunatamente, i dizionari di Python dispongono di un metodo specifico ideato proprio per situazioni come queste: il metodo get(). A questo passiamo due parametri: la chiave per il valore che stiamo cercando, e un valore di default come una sorta di "paracadute d'emergenza", qualora la chiave richiesta non esista.

Richiamiamo il metodo get() sul nostro dizionario ita_eng e passiamogli la chiave birra, e come valore di default la stringa "Chiave non trovata, mi spiace!"

>>> ita_eng.get("birra", "Chiave non trovata, mi spiace!")

# output
'Chiave non trovata, mi spiace!'

Proviamo anche a chiamare il metodo passandoli una chiave stavolta esistente:

>>> ita_eng.get("ciao", "Chiave non trovata!!!")

# output
'hello'

Il Metodo setdefault()

Parallelamente a quanto fatto col metodo get(), ci saranno dei momenti in cui a seconda della complessità di ciò che stiamo facendo, potremmo avere la necessità di creare una coppia chiave valore qualora una chiave non sia già presente e associata a un valore nel dizionario.

Restando sull'esempio precedente, supponiamo di voler verificare se sia presente la chiave birra nel nostro dizionario e di volerla aggiungere assieme ad un valore di default qualora non sia già presente

>>> ita_eng
{'ciao': 'hello', 'arrivederci': 'goodbye', 'uova': 'eggs', 'gatto': 'cat', 'arancia': 'orange'}

>>> ita_eng.setdefault("birra", "beer")
"beer"

>>> ita_eng
{'ciao': 'hello', 'arrivederci': 'goodbye', 'uova': 'eggs', 'gatto': 'cat', 'arancia': 'orange', 'birra': 'beer'}

Il metodo setdefault() ha anzitutto cercato la chiave birra all'interno del dizionario ita_eng, e visto che la chiave non esisteva ha creato una coppia chiave-valore col valore beer da noi passato!