Dizionari 1 - Introduzione
Scarica zip esercizi
I dizionari sono dei contenitori mutabili che ci consentono di associare velocemente voci dette chiavi a dei valori
Le chiavi sono immutabili, non hanno ordine e non vi possono essere duplicati
I valori possono essere duplicati
Data una chiave, possiamo reperire velocemente il valore corrispondente.
Che fare
scompatta lo zip in una cartella, dovresti ottenere qualcosa del genere:
dictionaries
dictionaries1.ipynb
dictionaries1-sol.ipynb
dictionaries2.ipynb
dictionaries2-sol.ipynb
dictionaries3.ipynb
dictionaries3-sol.ipynb
dictionaries4.ipynb
dictionaries4-sol.ipynb
dictionaries5-chal.ipynb
jupman.py
ATTENZIONE: Per essere visualizzato correttamente, il file del notebook DEVE essere nella cartella szippata.
apri il Jupyter Notebook da quella cartella. Due cose dovrebbero aprirsi, prima una console e poi un browser. Il browser dovrebbe mostrare una lista di file: naviga la lista e apri il notebook
dictionaries1.ipynb
Prosegui leggendo il file degli esercizi, ogni tanto al suo interno troverai delle scritte ESERCIZIO, che ti chiederanno di scrivere dei comandi Python nelle celle successive.
Scorciatoie da tastiera:
Per eseguire il codice Python dentro una cella di Jupyter, premi
Control+Invio
Per eseguire il codice Python dentro una cella di Jupyter E selezionare la cella seguente, premi
Shift+Invio
Per eseguire il codice Python dentro una cella di Jupyter E creare una nuova cella subito dopo, premi
Alt+Invio
Se per caso il Notebook sembra inchiodato, prova a selezionare
Kernel -> Restart
Creare un dizionario
Nella vita di tutti i giorni quando pensiamo ad un dizionario tipicamente ci riferiamo ad un libro che data una voce (per es. 'sedia'
), ci permette rapidamente di trovare la relativa descrizione (es. 'un mobile per sedersi'
).
In Python abbiamo una struttura dati chiamata dict
che ci consente di rappresentare comodamente i dizionari.
Riprendendo l’esempio di prima, potremmo creare un dict
con diverse voci così:
[2]:
{'sedia':'un mobile per sedersi',
'armadio':'un mobile a ripiani',
'lampadario': 'un apparecchio di illuminazione'
}
[2]:
{'sedia': 'un mobile per sedersi',
'armadio': 'un mobile a ripiani',
'lampadario': 'un apparecchio di illuminazione'}
Chiariamo un momento i nomi:
I dizionari sono dei contenitori mutabili che ci consentono di associare velocemente voci dette chiavi a dei valori.
La definizione ci dice che le voci in Python vengono chiamate chiavi (nell esempio 'sedia'
, 'armadio'
etc), mentre quelle che nell’esempio sono descrizioni ('un mobile per sedersi'
) in Python le chiamiamo valori.
Quando creaiamo un dizionario, scriviamo prima una graffa {
, poi la facciamo seguire da una serie di coppie chiave :
valore, ciascuna seguita da una virgola ,
(tranne l’ultima, in cui la virgola è opzionale). Alla fine chiudiamo con una graffa }
.
Mettere spazi o ritorni a capo all’interno è opzionale. Quindi possiamo scrivere anche così:
[3]:
{
'sedia' : 'un mobile per sedersi',
'armadio' : 'un mobile a ripiani',
'lampadario': 'un apparecchio di illuminazione'
}
[3]:
{'sedia': 'un mobile per sedersi',
'armadio': 'un mobile a ripiani',
'lampadario': 'un apparecchio di illuminazione'}
O anche tutto su una riga:
[4]:
{'sedia':'un mobile per sedersi','armadio':'un mobile a ripiani','lampadario':'un apparecchio di illuminazione'}
[4]:
{'sedia': 'un mobile per sedersi',
'armadio': 'un mobile a ripiani',
'lampadario': 'un apparecchio di illuminazione'}
Nota che se usiamo parole brevi Python probabilmente stamperà il dizionario comunque su una riga:
[5]:
{'barca': 'remo',
'auto': 'ruota',
'aereo': 'ala'}
[5]:
{'barca': 'remo', 'auto': 'ruota', 'aereo': 'ala'}
Mettere una virgola anche dopo l’ultima coppia non provoca errori:
[6]:
{
'barca': 'remo',
'auto': 'ruota',
'aereo': 'ala', # nota virgola 'extra'
}
[6]:
{'barca': 'remo', 'auto': 'ruota', 'aereo': 'ala'}
Vediamo come viene rappresentato un dizionario in Python Tutor - per agevolarci, lo assegnamo alla variabile diz
[7]:
# AFFINCHE' PYTHON TUTOR FUNZIONI, RICORDATI DI ESEGUIRE QUESTA CELLA con Shift+Invio
# (basta eseguirla una volta sola, la trovi anche all'inizio di ogni foglio)
import jupman
[8]:
diz = {
'sedia' : 'un mobile per sedersi',
'armadio' : 'un mobile a ripiani',
'lampadario': 'un apparecchio di illuminazione'
}
print(diz)
jupman.pytut()
{'sedia': 'un mobile per sedersi', 'armadio': 'un mobile a ripiani', 'lampadario': 'un apparecchio di illuminazione'}
[8]:
Notiamo che una volta eseguito, appare una freccia da diz
che punta ad una regione di memoria arancione/gialla. Le chiavi hanno sfondo arancione, mentre i corrispondenti valori hanno sfondo giallo. Dalle frecce e colori, si può intuire che quando si parla di assegnazioni di variabili, i dizionari si comportano come altre strutture dati mutabili, come le liste e gli insiemi.
DOMANDA: Guarda il codice seguente, e prova ad immaginare cosa succederà durante l’esecuzione - alla fine, come sarà organizzata la memoria? Cosa sarà stampato? Dove andranno le frecce?
[9]:
da = {
'sedia' : 'un mobile per sedersi',
'armadio' : 'un mobile a ripiani',
'lampadario': 'un apparecchio di illuminazione'
}
db = {
'barca': 'remo',
'auto': 'ruota',
'aereo': 'ala'
}
dc = db
db = da
da = dc
dc = db
#print(da)
#print(db)
#print(dc)
jupman.pytut()
[9]:
Le chiavi
Cerchiamo di capire meglio quali chiavi possiamo mettere riguardando la definizione:
I dizionari sono dei contenitori mutabili che ci consentono di associare velocemente voci dette chiavi a dei valori
Le chiavi sono immutabili, non hanno ordine e non vi possono essere duplicati
I valori possono essere duplicati
DOMANDA: guarda bene le parole in grassetto - ti viene in mente una struttura dati già vista che ha quelle caratteristiche?
Mostra rispostaLe chiavi sono immutabili
DOMANDA: La definizione non impone di usare per forza stringhe come chiavi, possiamo usare anche altri tipi. Ma possiamo usare tutti quelli che vogliamo?
Per ciascuno degli esempi seguenti, prova a dire se il dizionario si può creare o se otterremo un errore (quale?). Controlla come sono rappresentati in Python Tutor.
interi
{ 4 : 'gatti', 3 : 'cani' }
float
{ 4.0 : 'gatti', 3.0 : 'cani' }
stringhe
{ 'a' : 'gatti', 'b' : 'cani' }
liste
{ [1,2] : 'zam', [3,4] : 'zum' }
tuple
{ (1,2) : 'zam', (4,3) : 'zum' }
insiemi
{ {1,2} : 'zam', {3,4} : 'zum' }
altri dizionari (guarda la prima parte della definizione !)
{ {'a':'x','b':'y'} : 'zam', {'c':'w','d':'z'} : 'zum' }
Le chiavi non hanno ordine
In un dizionario che possiamo trovare nella vita reale, le voci sono sempre ordinate secondo qualche criterio, (tipicamente in ordine alfabetico)
Con Python invece dobbiamo considerare un’importante differenza:
Le chiavi sono immutabili, non hanno ordine e non vi possono essere duplicati
Quando diciamo che una collezione ‘non ha ordine’, significa che l’ordine degli elementi che vediamo quando li inseriamo o stampiamo non ha alcuna importanza nel determinare se una collezione è uguale ad un’altra. Nel caso dei dizionari significa che cambiando l’ordine in cui sono specificate le coppie, otteniamo dizionari che Python considera uguali.
Per esempio, i seguenti dizionari sono da considerarsi tutti uguali:
[10]:
{
'navi' :'porto',
'aerei': 'aereoporto',
'treni': 'stazione'
}
[10]:
{'navi': 'porto', 'aerei': 'aereoporto', 'treni': 'stazione'}
[11]:
{
'aerei': 'aereoporto',
'navi' :'porto',
'treni': 'stazione'
}
[11]:
{'aerei': 'aereoporto', 'navi': 'porto', 'treni': 'stazione'}
[12]:
{
'treni': 'stazione',
'navi' : 'porto',
'aerei': 'aereoporto',
}
[12]:
{'treni': 'stazione', 'navi': 'porto', 'aerei': 'aereoporto'}
Stampare un dizionario: avrai notato che Jupyter stampa sempre le chiavi nello stesso ordine alfabetico. Questa è una cortesia che ci fa Jupyter, ma non lasciarti ingannare! Se proviamo una stampa nativa con print
otterremo un risultato diverso!
[13]:
print({
'navi' :'porto',
'aerei': 'aereoporto',
'treni': 'stazione'
})
{'navi': 'porto', 'aerei': 'aereoporto', 'treni': 'stazione'}
Duplicati delle chiavi
Le chiavi sono immutabili, non hanno ordine e non vi possono essere duplicati
Possiamo chiederci come Python gestisca i duplicati nelle chiavi. Proviamo di proposito a creare una coppia duplicata:
[14]:
{
'sedia' : 'un mobile per sedersi',
'sedia' : 'un mobile per sedersi',
'lampadario': 'un apparecchio di illuminazione'
}
[14]:
{'sedia': 'un mobile per sedersi',
'lampadario': 'un apparecchio di illuminazione'}
Notiamo che Python non si è lamentato e ha silenziosamente scartato il duplicato. E se provassimo ad inserire una coppia con stessa chiave ma valore diverso?
[15]:
{
'sedia' : 'un mobile per sedersi',
'sedia' : 'appoggio con schienale',
'lampadario': 'un apparecchio di illuminazione'
}
[15]:
{'sedia': 'appoggio con schienale',
'lampadario': 'un apparecchio di illuminazione'}
Notiamo che Python ha mantenuto solo l’ultima coppia.
I valori
Riguardiamo la definizione:
I dizionari sono dei contenitori mutabili che ci consentono di associare velocemente voci dette chiavi a dei valori.
Le chiavi sono immutabili, non hanno ordine e non vi possono essere duplicati
I valori possono essere duplicati
Pare che per i valori vi siano meno vincoli rispetto alle chiavi
DOMANDA: Per ciascuno degli esempi seguenti, prova a dire se il dizionario si può creare o se otterremo un errore (quale?). Controlla come sono rappresentati in Python Tutor.
interi
{ 'a':3, 'b':4 }
interi duplicati
{ 'a':3, 'b':3 }
float
{ 'a':3.0, 'b':4.0 }
stringhe
{ 'a' : 'ghiaccio', 'b' : 'fuoco' }
liste
{ 'a' : ['t','w'], 'b' : ['x'], 'c' : ['y','z','k'] }
liste duplicate
{ 'a' : ['x','y','z'], 'b' : ['x','y','z'] }
liste contenenti duplicati
{ 'a' : ['x','y','y'], 'b' : ['z','y','z'] }
tuple
{ 'a': (6,9,7), 'b': (8,1,7,4) }
insiemi
{ 'a' : {6,5,6}, 'b' : {2,4,1,5} }
dizionari
{ 'a': { 'x':3, 'y':9 }, 'b': { 'x':3, 'y':9, 'z':10 }, }
Dizionario vuoto
Possiamo creare un dizionario vuoto scrivendo {}
:
ATTENZIONE: DA NON CONFONDERSI CON L’INSIEME VUOTO !!
[16]:
{}
[16]:
{}
[17]:
type({})
[17]:
dict
Un dizionario è una collezione, e come già visto (con liste, tuple e insiemi), possiamo creare un dizionario vuoto scrivendo il suo tipo dict
seguito da parentesi tonde:
[18]:
dict()
[18]:
{}
Vediamo come viene rappresentato in Python Tutor:
[19]:
diz = dict()
jupman.pytut()
[19]:
Chiavi e valori eterogenei
Finora abbiamo sempre usato chiavi tutte dello stesso tipo e valori tutti dello stesso tipo, ma non è obbligatorio. Basta che i tipi delle chiavi siano immutabili:
[20]:
{
"a": 3,
"b": ["una", "lista"],
7 : ("questa","è","una","tupla")
}
[20]:
{'a': 3, 'b': ['una', 'lista'], 7: ('questa', 'è', 'una', 'tupla')}
NOTA: Sebbene mischiare tipi sia possibile, è sconsigliabile!
Buttare nel dizionario tipi diversi spesso porta sfortuna, nel senso che aumenta la probabilità di incorrere in bug.
DOMANDA: Guarda le seguenti espressioni, e per ciascuna cerca di indovinare quale risultato producono (o se danno errore):
{'a':'b' , 'c':'d' }
{'a b':'c', 'c d':'e f'}
{'a' = 'c', 'b' = 'd'}
{'a':'b': 'c':'d'}
{ "1":[2,3], "2,3":1, }
type({'a:b,c:d'})
{'a':'b'; 'c':'d'}
{'a:b', 'c:d'}
{5,2: 4,5}
{1:2, 1:3}
{2:1, 3:1}
{'a':'b', 'c':'d',}
type({'a','b', 'c','d'})
{'a':'b', 'c':'d', 'e','f'}
{{}: 2}
{(1,2):[3,4]}
{[1,2]:(3,4)}
{'[1,2]':(3,4)}
{{1,2}:(3,4)}
{len({1,2}):(3,4)}
{5:{'a':'b'}}
{"a":{1:2}}
{"a":{[1]:2}}
{"a":{1:[2]}}
{["a":{1:[2]}]}
set([{2:4}])
Esercizio - barone
Data una lista
di esattamente 6 caratteri, costruisci un dizionario diz
come riportato di seguito:
Esempio 1 - data:
lista = ['b', 'a', 'r', 'o', 'n', 'e']
dopo il tuo codice deve risultare (NOTA: l’ordine delle chiavi NON conta!)
>>> diz
{'b': ['a', 'r', 'o', 'n', 'e'],
('b', 'a', 'r', 'o', 'n', 'e'): {'a', 'b', 'e', 'n', 'o', 'r'},
('b', 'a', 'b', 'a'): ['r', 'o', 'r', 'o', 'n', 'e', 'n', 'e'],
'b/a/r/o/n/e': {'b': 'a', 'r': 'o', 'n': 'e'}}
Esempio 2 - data:
lista = ['p', 'r', 'i', 'o', 'r', 'e']
deve risultare:
>>> diz
{'p': ['r', 'i', 'o', 'r', 'e'],
('p', 'r', 'i', 'o', 'r', 'e'): {'e', 'i', 'o', 'p', 'r'},
('p', 'r', 'p', 'r'): ['i', 'o', 'i', 'o', 'r', 'e', 'r', 'e'],
'p/r/i/o/r/e': {'p': 'r', 'i': 'o', 'r': 'e'}}
USA solo
lista
IMPORTANTE: NON scrivere costanti stringa (quindi es. niente
"barone"
,"b"
….)
[21]:
lista = ['b', 'a', 'r', 'o', 'n', 'e']
lista = ['p', 'r', 'i', 'o', 'r', 'e']
# scrivi qui
Dizionario da sequenza di coppie
Possiamo ottenere un dizionario specificando come parametro della funzione dict
una sequenza di coppie chiave/valore, per esempio potremmo passare una lista di tuple:
[22]:
dict( [
('farina',500),
('uova',2),
('zucchero',200),
])
[22]:
{'farina': 500, 'uova': 2, 'zucchero': 200}
Possiamo usare anche altre sequenze, l’importante è che le sottosequenze siano tutte da due elementi. Qua per esempio abbiamo una tupla di liste:
[23]:
dict( (
['farina',500],
['uova',2],
['zucchero',200],
))
[23]:
{'farina': 500, 'uova': 2, 'zucchero': 200}
Se una sottosequenza ha un numero di elementi diverso da due, otteniamo questo errore:
>>> dict( (
['farina',500],
['uova','marce', 3,],
['zucchero',200],
))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-88-563d301b4aef> in <module>
2 ['farina',500],
3 ['uova','marce', 3,],
----> 4 ['zucchero',200],
5 ))
ValueError: dictionary update sequence element #1 has length 3; 2 is required
DOMANDA: Compara i seguenti codici. Fanno la stessa cosa? Se sì, quale preferiresti?
dict( {
('a',5),
('b',8),
('c',3)
} )
dict( (
{'a',5},
{'b',8},
{'c',3}
)
)
DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):
dict('abcd')
dict(['ab','cd'])
dict(['a1','c2'])
dict([])
dict(())
dict((' ',)) # nasty
Esercizio - galattico veramente
Date alcune variabili usa il costruttore da sequenze di coppie per ottenere la variabile diz
.
NON usare costanti stringa nel codice, e neanche numeri particolari (quindi es. niente
'Ga'
nè759
). Usare indici è invece consentito.
Esempio 1 - date:
s = 'Ga'
t = ('LA','tt')
l1 = ['Ic','Co','Ve']
l2 = ['Ra','Me','Nt']
l3 = [[['EEE','...']]]
n = 43.759
Dopo il tuo codice, deve risultare (NOTA: l’ordine delle chiavi NON conta!)
>>> diz
{'G': 'a',
'LA': 'tt',
'I': 'c',
'C': 'o',
'V': 'e',
'R': 'a',
'M': 'e',
'N': 't',
'EEE': '...',
'43': '759'}
Esempio 2 - date:
s = 'Sp'
t = ('Az','ia')
l1 = ['Le','Si','De']
l2 = ['Ra','Le','In']
l3 = [[['CREDIBBILE','!!!!!']]]
n = 8744.92835
deve risultare:
>>> diz
{'S': 'i',
'Az': 'ia',
'L': 'e',
'D': 'e',
'R': 'a',
'I': 'n',
'CREDIBBILE': '!!!!!',
'8744': '92835'}
[24]:
s = 'Ga'
t = ('LA','tt')
l1 = ['Ic','Co','Ve']
l2 = ['Ra','Me','Nt']
l3 = [[['EEE','...']]]
n = 43.759
#s = 'Sp'
#t = ('Az','ia')
#l1 = ['Le','Si','De']
#l2 = ['Ra','Le','In']
#l3 = [[['CREDIBBILE','!!!!!']]]
#n = 8744.92835
# scrivi qui
Dizionario da parametri con nome
Come ulteriore metodo di creazione, possiamo specificare le chiavi come se fossero parametri con nome:
[25]:
dict(a=5,b=6)
[25]:
{'a': 5, 'b': 6}
ATTENZIONE: in questo caso le chiavi sono soggette alle stesse restrittive regole dei nomi di parametri di funzione!
Per esempio, usando le graffe questo dizionario è perfettamente legittimo:
[26]:
{'a b' : 2,
'c d' : 6}
[26]:
{'a b': 2, 'c d': 6}
Ma se proviamo a crearlo usando a b
come argomento di dict
, avremo dei problemi:
>>> dict(a b=2, c d=6)
File "<ipython-input-97-444f8661585a>", line 1
dict(a b=2, c d=6)
^
SyntaxError: invalid syntax
Avremo dei problemi anche usando stringhe:
>>> dict('a b'=2,'c d'=6)
File "<ipython-input-98-45aafbb56e81>", line 1
dict('a b'=2,'c d'=6)
^
SyntaxError: keyword can't be an expression
E attenzione a furbate tipo usare variabili, non otterremo il risultato desiderato:
[27]:
ka = 'a b'
kc = 'c d'
dict(ka=2,kc=6)
[27]:
{'ka': 2, 'kc': 6}
DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):
dict(3=5,2=8)
dict('costi'=9,'ricavi'=15)
dict(_costi=9,_ricavi=15)
dict(33trentini=5)
dict(trentini33=5)
dict(trentini_33=5)
dict(trentini-33=5)
dict(costi=1=2,ricavi=3=3)
dict(costi=1==2,ricavi=3==3)
v1 = 6 v2 = 8 dict(k1=v1,k2=v2)
Copiare un dizionario
Ci sono due modi di copiare un dizionario, si può fare una copia superficiale (shallow copy) oppure una copia in profondità (deep copy).
Copia superficiale
E’ possibile creare una copia superficiale (shallow copy) di un dizionario passando alla funzione dict
un’altro dizionario:
[28]:
da = {'x':3,
'y':5,
'z':1}
[29]:
db = dict(da)
[30]:
print(da)
{'x': 3, 'y': 5, 'z': 1}
[31]:
print(db)
{'x': 3, 'y': 5, 'z': 1}
In Python Tutor vedremo apparire due regioni di memoria separate:
[32]:
da = {'x':3,
'y':5,
'z':1}
db = dict(da)
jupman.pytut()
[32]:
DOMANDA: possiamo scrivere così? Rispetto all’esempio precedente, otterremo risultati diversi?
[33]:
da = {'x':3,
'y':5,
'z':1}
db = dict(dict(da))
jupman.pytut()
[33]:
Valori mutabili: Nell’esempio abbiamo usato valori interi, che sono immutabili. E se provassimo dei valori mutabili come delle liste, che succederebbe?
[34]:
da = {'x':['a','b','c'],
'y':['d'],
'z':['e','f']}
db = dict(da)
jupman.pytut()
[34]:
Se provi ad eseguire Python Tutor, vedrai un’esplosione di frecce che vanno dal nuovo dizionario db
ai valori di da
(che sono liste). Niente paura ! Nel prossimo foglio spiegheremo meglio il significato, per il momento tieni nota che con la copia superficiale di valori mutabili il nuovo dizionario avrà in comune regioni di memoria con il dizionario originale.
Copia in profondità
Quando ci sono regioni di memoria mutabili condivise come nel caso qua sopra, è più probabile introdurre bug.
Per aver regioni di memoria completamente separate, possiamo usare la copia in profondità (deep copy).
Per usarla, dobbiamo prima dire a Python che intendiamo usare funzioni presenti nel modulo copy
, poi potremo usare la funzione deepcopy
, a cui passeremo il dizionario da copiare:
[35]:
import copy
da = {'x':['a','b','c'],
'y':['d'],
'z':['e','f']}
db = copy.deepcopy(da)
jupman.pytut()
[35]:
Se esegui il codice in Python Tutor, noterai come partendo con la freccia da db
, finiremo in una regione di memoria arancione/gialla completamente nuova che non condivide nulla con la regione di memoria puntata da da
.
DOMANDA: Guarda il codice seguente - dopo la sua esecuzione, vedrai frecce che da db
arrivano ad elementi di da
?
[36]:
da = {'x': {1,2,3},
'y': {4,5}}
db = dict(da)
jupman.pytut()
[36]:
Prosegui
Prosegui con Dizionari 2