Dizionari 2 - operatori

Scarica zip esercizi

Naviga file online

Per manipolare i dizionari vi sono diversi operatori:

Operatore

Sintassi

Ritorna

Descrizione

lunghezza

len(dict)

int

Ritorna il numero di chiavi

lettura

dict[chiave]

obj

Ritorna il valore associato alla chiave

modifica

dict[chiave] = valore

Aggiunge o modifica il valore associato ad una chiave

rimozione

del dict[chiave]

Rimuove la coppia chiave/valore

appartenenza

chiave in dict

bool

Ritorna True se chiave è presente nel dizionario

uguaglianza

==,!=

bool

Controlla se due dizionari sono uguali o differenti

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

len

E’ possibile ottenere il numero di associazioni chiave/valore presente in un dizionario usando la funzione len:

[2]:
len({'a':5,
     'b':9,
     'c':7
})
[2]:
3
[3]:
len({3:8,
     1:3
})
[3]:
2
[4]:
len({})
[4]:
0

DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. len(dict())
    
  2. len({'a':{}})
    
  3. len({(1,2):{3},(4,5):{6},(7,8):{9}})
    
  4. len({1:2,1:2,2:4,2:4,3:6,3:6})
    
  5. len({1:2,',':3,',':4,})
    
  6. len(len({3:4,5:6}))
    

Leggere un valore

In fondo alla definizione dei dizionari, è riportato

Data una chiave, possiamo reperire velocemente il valore corrispondente.

Come possiamo specificare la chiave di ricerca? Basta usare le quadre [ ], un po’ come abbiamo già fatto per le liste:

[5]:
diz = {  'sedia'     : 'un mobile per sedersi',
         'armadio'   : 'un mobile a ripiani',
         'lampadario': 'un apparecchio di illuminazione'
}
[6]:
diz['sedia']
[6]:
'un mobile per sedersi'
[7]:
diz['lampadario']
[7]:
'un apparecchio di illuminazione'

ATTENZIONE Quello che mettiamo tra parentesi quadre deve essere una chiave presente nel dizionario

Se mettiamo chiavi non presenti, otterremo un errore:

>>> diz['tavolo']

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-19-ee891f51417b> in <module>
----> 1 diz['tavolo']

KeyError: 'tavolo'

Disordine veloce

Quando diamo una chiave a Python, quanto è veloce a reperire il valore corrispondente? Tanto, così veloce che la velocità non dipende dalla dimensione del dizionario. Che sia piccolo o enorme, data una chiave troverà il valore associato in circa il medesimo tempo.

Quando abbiamo in mano un dizionario nella vita reale, tipicamente abbiamo una voce da cercare e lo sfogliamo finchè troviamo la voce ordinata: il fatto che le voci siano ordinate è quello che ci consente di trovare rapidamente la voce.

Potremmo aspettarci lo stesso anche in Python, invece guardando la definizione troviamo una notevole differenza:

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

Se le chiavi non sono ordinate, come fa Python ad essere veloce a reperire i valori? La rapidità nasce dal fatto che Python memorizza le chiavi con un sistema con basato sugli hash simile al meccanismo impiegato per gli insiemi. Il prezzo da pagare per noi è l’imposizione di dover usare chiavi di tipo immutabile.

DOMANDA: Se volessimo stampare il valore 'un apparecchio di illuminazione' che vediamo in fondo al dizionario, senza sapere che corrisponde a 'lampadario', avrebbe senso scrivere qualcosa del genere ?:

arredo = {  'sedia'     : 'un mobile per sedersi',
            'armadio'   : 'un mobile a ripiani',
            'lampadario': 'un apparecchio di illuminazione'
}

print( arredo[2] )
Mostra risposta

DOMANDA: Guarda le seguenti espressioni, e per ciascuna cerca di indovinare quale risultato producono (o se danno errore):

kabbalah = {
    1 : 'Progresso',
    3 : 'Amore',
    5 : 'Creazione'
}
  • kabbalah[0]
    
  • kabbalah[1]
    
  • kabbalah[2]
    
  • kabbalah[3]
    
  • kabbalah[4]
    
  • kabbalah[5]
    
  • kabbalah[-1]
    
Mostra risposta

DOMANDA: Guarda le seguenti espressioni, e per ciascuna cerca di indovinare quale risultato producono (o se danno errore):

  1. {'a':4,'b':5}('a')
    
  2. {1:2,2:3,3:4}[2]
    
  3. {'a':1,'b':2}['c']
    
  4. {'a':1,'b':2}[a]
    
  5. {'a':1,'b':2}[1]
    
  6. {'a':1,'b':2,'c':3}['c']
    
  7. {'a':1,'b':2,'c':3}[len(['a','b','c'])]
    
  8. {(3,4):(1,2)}[(1,2)]
    
  9. {(1,2):(3,4)}[(1,2)]
    
  10. {[1,2]:[3,4]}[[1,2]]
    
  11. {'a','b','c'}['a']
    
  12. {'a:b','c:d'}['c']
    
  13. {'a':4,'b':5}{'a'}
    
  14. d1 = {'a':'b'}
    d2 = {'b':'c'}
    print(d1[d2['c']])
    
  15. d1 = {'a':'b'}
    d2 = {'b':'c'}
    print(d2[d1['a']])
    
  16. {}[]
    
  17. {[]:3}[[]]
    
  18. {1:7}['1']
    
  19. {'':7}"[]"
    
  20. {'':7}[""]
    
  21. {"":7}['']
    
  22. {'"':()}['']
    
  23. {():7}[()]
    
  24. {(()):7}[()]
    
  25. {(()):7}[((),)]
    

Esercizio - z7

✪ Dato un dizionario diz1 con chiavi 'b' e 'c' associate a numeri, crea un dizionario diz2 che abbia una chiave 'z' associata alla somma dei valori delle chiavi 'b' e 'c' di diz1

  • il tuo codice deve funzionare per qualunque diz1 con chiavi 'b' e 'c'

Esempio - dato:

diz1 = {'a':6, 'b':2,'c':5}

Dopo il tuo codice, deve risultare:

>>> print(diz2)
{'z': 7}
Mostra soluzione
[8]:

diz1 = {'a':6, 'b':2,'c':5} # scrivi qui

Scrivere nel dizionario

Possiamo scrivere in un dizionario?

I dizionari sono dei contenitori mutabili che ci consentono di associare velocemente voci dette chiavi a dei valori

La definizione parla di mutabilità, quindi una volta creati, possiamo successivamente modificarli.

I dizionari sono collezioni di coppie chiave/valore, e tra le modifiche possibili troviamo:

  1. aggiunta di una coppia chiave/valore

  2. associare una chiave esistente ad un valore diverso

  3. rimuovere una coppia chiave/valore

Scrivere - aggiunta chiave/valore

Supponiamo di aver creato il nostro dizionario arredo

[9]:
arredo = {  'sedia'     : 'un mobile per sedersi',
            'armadio'   : 'un mobile a ripiani',
            'lampadario': 'un apparecchio di illuminazione'
}

e vogliamo in seguito aggiungere una definizione per 'divano'. Possiamo riusare la variabile arredo seguita da quadre con dentro la chiave che vogliamo aggiungere ['divano'] e dopo le quadre metteremo un segno di uguale =

[10]:
arredo['divano'] = 'mobile per rilassarsi'

Nota che Jupyter non ha mostrato risultati, perchè l’operazione precedente è un comando di assegnamento (solo le espressioni generano risultati).

Ma qualcosa comunque internamente nella memoria è successo, lo possiamo verificare stampando arredo:

[11]:
arredo
[11]:
{'sedia': 'un mobile per sedersi',
 'armadio': 'un mobile a ripiani',
 'lampadario': 'un apparecchio di illuminazione',
 'divano': 'mobile per rilassarsi'}

Notiamo che il dizionario associato alla variabile arredo è stato MODIFICATO con l’aggiunta del divano.

Quando aggiungiamo una coppia chiave/valore, possiamo usare tipi eterogenei:

[12]:
bidone = {'bla':3,
           4 : 'boh',
           (7,9) : ['spaz','zatura']
         }
[13]:
bidone[5.0] = 'un float'
[14]:
bidone
[14]:
{'bla': 3, 4: 'boh', (7, 9): ['spaz', 'zatura'], 5.0: 'un float'}

E siamo soggetti agli stessi vincoli sulle chiavi che abbiamo durante la creazione, quindi possiamo solo usare chiavi immutabili. Se proviamo ad immettere un tipo mutabile come per es. una lista, otteniamo un errore:

>>> bidone[ ['una', 'lista']  ] = 8

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-51-195ac9c21bcd> in <module>
----> 1 bidone[ ['una', 'lista']  ] = 8

TypeError: unhashable type: 'list'

DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. diz = {1:'a'}
    diz[2] = 'a'
    print(diz)
    
  2. diz = {}
    print(len(diz))
    diz['a'] = 'b'
    print(len(diz))
    
  3. diz1 = {'a':3, 'b':4}
    diz2 = diz1
    diz1['a'] = 5
    print(diz1)
    print(diz2)
    
  4. diz1 = {'a':3, 'b':4}
    diz2 = dict(diz1)
    diz1['a'] = 5
    print(diz1)
    print(diz2)
    
  5. la = ['a','c']
    diz = {'a':3,
           'b':4,
           'c':5}
    diz['d'] = diz[la[0]] + diz[la[1]]
    print(diz)
    
  6. diz = {}
    diz[()]: ''
    diz[('a',)]: 'A'
    diz[('a','b')]: 'AB'
    print(diz)
    
  7. la = [5,8,6,9]
    diz = {}
    diz[la[0]]=la[2]
    diz[la[2]]=la[0]
    print(diz)
    
  8. diz = {}
    diz[(4,5,6)[2]] = 'c'
    diz[(4,5,6)[1]] = 'b'
    diz[(4,5,6)[0]] = 'a'
    print(diz)
    
  9. diz1 = {
        'a' : 'x',
        'b' : 'x',
        'c' : 'y',
        'd' : 'y',
    }
    
    diz2 = {}
    diz2[diz1['a']] = 'a'
    diz2[diz1['b']] = 'b'
    diz2[diz1['c']] = 'c'
    diz2[diz1['d']] = 'd'
    print(diz2)
    

Scrivere - riassociare chiave

Supponiamo di voler cambiare la definizione di lampadario:

[15]:
arredo = {  'sedia'     : 'un mobile per sedersi',
            'armadio'   : 'un mobile a ripiani',
            'lampadario': 'un apparecchio di illuminazione'
}
[16]:
arredo['lampadario'] = 'un apparecchio di illuminazione appeso al soffitto'
[17]:
arredo
[17]:
{'sedia': 'un mobile per sedersi',
 'armadio': 'un mobile a ripiani',
 'lampadario': 'un apparecchio di illuminazione appeso al soffitto'}

Esercizio - officina

✪ MODIFICA il dizionario officina:

  1. poni il valore della chiave 'bulloni' uguale al valore della chiave 'tenaglie'

  2. incrementa il valore della chiave ruote di 1

  • il tuo codice deve funzionare per qualunque numero associato alle chiavi

  • NON creare nuovi dizionari, quindi niente linee che cominciano con officina = {

Esempio - dati:

officina = {'ruote':3,
            'bulloni':2,
            'tenaglie':5}

dopo il tuo codice, devi ottenere:

>>> print(officina)
{'ruote': 4, 'bulloni': 5, 'tenaglie': 5}
Mostra soluzione
[18]:
officina = {'ruote':3,
            'bulloni':2,
            'tenaglie':5}

# scrivi qui


DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. diz = {'a':'b'}
    diz['a'] = 'a'
    print(diz)
    
  2. diz = {'1':'2'}
    diz[1] = diz[1] + 5   # nasty
    print(diz)
    
  3. diz = {1:2}
    diz[1] = diz[1] + 5
    print(diz)
    
  4. d1 = {1:2}
    d2 = {2:3}
    d1[1] = d2[d1[1]]
    print(d1)
    

Scrivere - cancellare

Per cancellare una coppia chiave/valore esiste il comando speciale del. Prendiamo un dizionario:

[19]:
cucina = { 'pentole' : 3,
           'padelle': 7,
           'forchette' : 20
}

Se vogliamo eliminare la coppia 'padelle' : 7, scriveremo del seguito dal nome del dizionario e la chiave da eliminare tra quadre:

[20]:
del cucina['padelle']
[21]:
cucina
[21]:
{'pentole': 3, 'forchette': 20}

Cercare di cancellare una chiave inesistente produrrà un errore:

>>> del cucina['spinterogeno']

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-34-c0d541348698> in <module>
----> 1 del cucina['spinterogeno']

KeyError: 'spinterogeno'

DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. diz = {'a':'b'}
    del diz['b']
    print(diz)
    
  2. diz = {'a':'b', 'c':'d'}
    del diz['a']
    print(diz)
    
  3. diz = {'a':'b', 'c':'d'}
    del diz['a']
    del diz['a']
    print(diz)
    
  4. diz = {'a':'b'}
    new_diz = del diz['a']
    print(diz)
    print(new_diz)
    
  5. diz1 = {'a':'b', 'c':'d'}
    diz2 = diz1
    del diz1['a']
    print(diz1)
    print(diz2)
    
  6. diz1 = {'a':'b', 'c':'d'}
    diz2 = dict(diz1)
    del diz1['a']
    print(diz1)
    print(diz2)
    
  7. diz = {'a':'b'}
    del diz['c']
    print(diz)
    
  8. diz = {'a':'b'}
    diz.del('a')
    print(diz)
    
  9. diz = {'a':'b'}
    diz['a'] = None
    print(diz)
    

Esercizio - scrivania

Dato un dizionario scrivania:

scrivania = {
            'carta':5,
            'matite':2,
            'penne':3
}

scrivi del codice che lo MODIFICA in modo che dopo l’esecuzione del tuo codice, il dizionario appaia così:

>>> print(scrivania)
{'carta': 4,'matite': 2, 'temperino': 1}
  • NON scrivere linee che iniziano con scrivania = (questo creerebbe un nuovo dizionario, invece noi vogliamo modificare quello esistente)

Mostra soluzione
[22]:

scrivania = { 'carta':5, 'matite':2, 'penne':3 } # scrivi qui

Esercizio - giardino

Hai un dizionario giardino che associa nomi di oggetti presenti alla loro quantità. Ti vengono fornite:

  • una lista da_togliere contenente i nomi di esattamente 2 oggetti da eliminare

  • un dizionario da_aggiungere contenente 2 nomi di fiori associati alla loro quantità da aggiungere

MODIFICA il dizionario giardino secondo le quantità indicate da da_togliere (cancellando le chiavi) e da_aggiungere (incrementando i valori corrispondenti)

  • assumi che giardino contenga sempre gli oggetti indicati in da_togliere e da_aggiungere

  • assumi che da_aggiungere contenga sempre e solo tulipani e rose

Esempio:

da_togliere = ['erbacce', 'cartacce']
da_aggiungere = { 'tulipani': 4,
                  'rose'    : 2
}

giardino = { 'ortensie': 3,
             'tulipani': 7,
             'erbacce' : 10,
             'rose'    : 5,
             'cartacce': 6,
}

dopo il tuo codice, deve stampare

>>> print(giardino)
{'ortensie': 3, 'tulipani': 11, 'rose': 7}
Mostra soluzione
[23]:

da_togliere = ['erbacce', 'cartacce'] da_aggiungere = { 'tulipani': 4, 'rose' : 2 } giardino = { 'ortensie': 3, 'tulipani': 7, 'erbacce' : 10, 'rose' : 5, 'cartacce': 6, } # scrivi qui

Esercizio - traduzioni

Dati due dizionari en_it e it_es di traduzioni inglese-italiano e italiano-spagnolo, scrivi del codice che MODIFICA un terzo dizionario en_es mettendoci traduzioni dall’inglese allo spagnolo

  • assumi che en_it contenga sempre e solo le traduzioni di hello e road

  • assumi che it_es contenga sempre e solo le traduzioni di ciao e strada

  • nella soluzione, usa SOLO le costanti 'hello' e 'road', le altre che ti servono dovrai recuperarle usando i dizionari

  • NON creare un nuovo dizionario - quindi niente linee che iniziano con en_es = {

Esempio - dati:

en_it = {
    'hello' : 'ciao',
    'road' : 'strada'
}

it_es = {
    'ciao' : 'hola',
    'strada' : 'carretera'
}
en_es = {}

dopo il tuo codice, dovrà stampare:

>>> print(en_es)
{'hello': 'hola', 'road': 'carretera'}
Mostra soluzione
[24]:

en_it = { 'hello' : 'ciao', 'road' : 'strada' } it_es = { 'ciao' : 'hola', 'strada' : 'carretera' } en_es = {} # scrivi qui

Appartenenza con in

Per verificare se una chiave è presente in un dizionario, possiamo usare l’operatore in:

[25]:
'a' in {'a':5,'b':7}
[25]:
True
[26]:
'b' in {'a':5,'b':7}
[26]:
True
[27]:
'z' in {'a':5,'b':7}
[27]:
False

ATTENZIONE: in cerca nelle chiavi , non nei valori !

[28]:
5 in {'a':5,'b':7}
[28]:
False

Come sempre quando operiamo con chiavi, non possiamo cercare un oggetto che sia mutabile, come per esempio le liste:

>>> [3,5] in {'a':'c','b':'d'}

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-41-3e3e336117aa> in <module>
----> 1 [3,5] in {'a':'c','b':'d'}

TypeError: unhashable type: 'list'

not in

E’ possibile verificare la non appartenza con l’operatore not in:

[29]:
'z' not in {'a':5,'b':7}
[29]:
True
[30]:
'a' not in {'a':5,'b':7}
[30]:
False

Equivalentemente, possiamo usare quest’altra forma:

[31]:
not 'z' in {'a':5,'b':7}
[31]:
True
[32]:
not 'a' in {'a':5,'b':7}
[32]:
False

DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. ('a') in {'a':5}
    
  2. ('a','b') in {('a','b'):5}
    
  3. ('a','b',) in {('a','b'):5}
    
  4. ['a','b'] in {('a','b'):5}
    
  5. {3: 'q' in {'q':5}}
    
  6. {'q' not in {'q':0} : 'q' in {'q':0}}
    
  7. {'a' in 'b'}
    
  8. {'a' not in {'b':'a'}}
    
  9. len({'a':6,'b':4}) in {1:2}
    
  10. 'ab' in {('a','b'): 'ab'}
    
  11. None in {}
    
  12. None in {'None':3}
    
  13. None in {None:3}
    
  14. not None in {0:None}
    

Esercizio - Il timoniere

Al ristorante “Il Timoniere” viene servito un menu con esattamente 3 portate ciascuna abbinata ad un contorno. Le portate e i contorni sono numerati da 1 a 12. Vi sono molti clienti internazionali che non parlano bene l’italiano, quindi spesso indicano semplicemente un numero di portata. Non indicano mai un contorno.

Una volta ricevuta la richiesta, il cameriere dispone di un tablet con cui verifica con ‘Cambusapp’ se il piatto è già pronto con il contorno corretto. Scrivi del codice che dato un indice di portata mostra Truese questa è in cambusa abbinata alla portata, False altrimenti.

Esempio 1 - dati:

       # 1        2        3        4        5         6
menu = ['aringa','burro','orata','insalata', 'salmone','patate',

       # 7        8          9         10        11        12
        'tonno', 'fagioli', 'salmone','limone', 'aringa', 'insalata']

cambusa = {'orata':'insalata',
           'salmone':'patate',
           'aringa':'insalata',
           'tonno':'fagioli'}

richiesta = 1

Il programma mostrerà False, perchè non c’è l’associazione "aringa" : "burro" in cambusa

Esempio 2 - data:

richiesta = 3

il programma mostrerà True perchè c’è l’associazione "orata" : "insalata" in cambusa

Mostra soluzione
[33]:

richiesta = 1 # False #richiesta = 3 # True #richiesta = 5 # True #richiesta = 7 # True #richiesta = 9 # False #richiesta = 11 # True # 1 2 3 4 5 6 menu = ['aringa','burro','orata','insalata', 'salmone','patate', # 7 8 9 10 11 12 'tonno', 'fagioli', 'salmone','limone', 'aringa', 'insalata'] cambusa = {'orata':'insalata', 'salmone':'patate', 'aringa':'insalata', 'tonno':'fagioli'} # scrivi qui

Dizionari di sequenze

Finora abbiamo quasi sempre associato alle chiavi un solo valore. E se volessimo associarne di più? Per esempio, supponiamo di essere una biblioteca e vogliamo associare agli utenti i libri che hanno preso in prestito. Potremmo rappresentare il tutto come un dizionario in cui al nome di ciascun utente si associa una lista con i libri presi in prestito:

[34]:
prestiti = {'Marco': ['I Miserabili', 'Ulisse'],
            'Gloria': ['Guerra e pace'],
            'Rita': ['Shining','Dracula','1984']}

Vediamo come è rappresentato in Python Tutor:

[35]:
# 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
[36]:
prestiti = {'Marco': ['I Miserabili', 'Ulisse'],
            'Gloria': ['Guerra e pace'],
            'Rita': ['Shining','Dracula','1984']}
jupman.pytut()
[36]:
Python Tutor visualization

Se proviamo a scrivere l’espressione

[37]:
prestiti['Rita']
[37]:
['Shining', 'Dracula', '1984']

Python ci mostra la lista corrispondente. Quindi Python considera prestiti['Rita'] a tutti gli effetti come una lista, e come tale la possiamo usare. Per esempio, se volessimo accedere al libro unesimo della lista scriveremmo [1] dopo l’espressione

[38]:
prestiti['Rita'][1]
[38]:
'Dracula'

Equivalentemente, potremmo anche salvarci un puntatore alla lista assegnando l’espressione ad una variabile:

[39]:
lista_rita = prestiti['Rita']
[40]:
lista_rita
[40]:
['Shining', 'Dracula', '1984']
[41]:
lista_rita[1]
[41]:
'Dracula'

Rivediamo il tutto in Python Tutor:

[42]:
prestiti = {'Marco':  ['I Miserabili', 'Ulisse'],
            'Gloria': ['Guerra e pace'],
            'Rita':   ['Shining','Dracula','1984']}
lista_rita = prestiti['Rita']
print(lista_rita[1])

jupman.pytut()
Dracula
[42]:
Python Tutor visualization

Se esegui il codice in Python Tutor, noterai come nel momento in cui assegnamo lista_rita la lista corrispondente a Rita sembra ‘staccarsi’ dal dizionario. Questo è un solo effetto grafico causato da Python Tutor, dal punto di vista del dizionario non è cambiato nulla. L’intenzione è mostrare che la lista adesso è raggiungibile sia dal dizionario che dalla nuova variabile lista_rita.

Esercizio - prestiti

Scrivi del codice per recuperare e stampare:

  1. Il primo libro preso in prestito da Gloria ('Guerra e Pace') e l’ultimo preso in prestito da Rita ('1984')

  2. Il numero di libri presi in prestito da Rita

  3. True se tutti tra Marco, Gloria e Rita hanno preso in prestito almeno un libro, False altrimenti

Mostra soluzione
[43]:
prestiti = {'Marco':  ['I Miserabili', 'Ulisse'],
            'Gloria': ['Guerra e pace'],
            'Rita':   ['Shining','Dracula','1984']}

# scrivi qui


1. Il primo libro preso in prestito da Gloria è Guerra e pace
   L'ultimo libro preso in prestito da Rita è 1984
2. Rita ha preso in prestito 3 libro/i
3. Hanno preso tutti in prestito almeno un libro? True

Esercizio - La baia dello squalo

La West India Company ti ha richiesto di compiere una esplorazione nei mari tropicali noti per le specie pericolose che popolano le loro acque. Ti viene fornita una mappa che associa dei luoghi alle specie ritrovate:

mappa = {
     "Baia dello Squalo"        : ["squali"],
     "Estuario della Malasorte" : ["coccodrilli", "piraña"],
     "Fossa del Naufragio"      : ["orche assassine", "pesci tigre"],
}

Ti vengono altresì date delle indicazioni vaghe su come aggiornare la mappa, usando queste variabili:

luogo = "Estuario della Malasorte"
pericoli = ["murene", "polpo blu maculato"]
viaggio = "Largo delle Vele Sommerse"
esplorazione = ['barracuda', 'meduse']

Prova a scrivere del codice che usando le variabili qua sopra (o dati dalla mappa stessa) MODIFICA mappa al fine di ottenere:

>>> mappa
{'Baia dello Squalo'        : ['squali'],
 'Estuario della Malasorte' : ['coccodrilli', 'piraña', 'meduse'],
 'Fossa del Naufragio'      : ['orche assassine', 'pesci tigre'],
 'Largo delle Meduse'       : ['barracuda', 'meduse', 'coccodrilli', 'piraña']}
  • IMPORTANTE: NON usare stringhe costanti nel tuo codice (quindi es. niente "Estuario della Malasorte" …). Costanti numeriche sono invece ammesse.

Mostra soluzione
[44]:

luogo = "Estuario della Malasorte" pericoli = ["murene", "polpo blu maculato"] viaggio = "Largo delle Vele Sommerse" esplorazione = ['barracuda', 'meduse'] mappa = { "Baia dello Squalo" : ["squali"], "Estuario della Malasorte" : ["coccodrilli", "piraña"], "Fossa del Naufragio" : ["orche assassine", "pesci tigre"], } # scrivi qui

Esercizio - Il mare della burrasca

La West India Company ti richiede di scrivere del codice per produrre una nuova mappa a partire da mappa1 e mappa2. La mappa nuova deve contenere tutte le voci di mappa1, espansa con le voci luogo1 e luogo2 da mappa2.

  • assumi che le voci luogo1 e luogo2 siano sempre presenti in mappa1 e mappa2

  • IMPORTANTE: dopo l’esecuzione del tuo codice, sia mappa1 che mappa2 devono risultare inalterate!

Esempio - date:

mappa1 = {
     "Baia dello Squalo" : ["squali"],
     "Estuario della Malasorte" : ["coccodrilli", "piraña"],
     "Mare della Burrasca" : ["barracuda", "meduse"],
}

mappa2 = {
     "Estuario della Malasorte" : ["murene", "pesci tigre"],
     "Mare della Burrasca" : ["polipi giganti"],
     "Fossa del Naufragio" : ["orche assassine"],
     "Lago dei Disperati" : ["vortici d'acqua"],
}

luogo1, luogo2 = "Estuario della Malasorte", "Mare della Burrasca"

Dopo il tuo cordice, deve risultare:

>>> nuova
{'Baia dello Squalo': ['squali'],
 'Estuario della Malasorte': ['coccodrilli', 'piraña', 'murene', 'pesci tigre'],
 'Mare della Burrasca': ['barracuda', 'meduse', 'polipi giganti']}
>>> mappa1  # inalterata!
{'Baia dello Squalo': ['squali'],
 'Estuario della Malasorte': ['coccodrilli', 'piraña'],
 'Mare della Burrasca': ['barracuda', 'meduse']}
>>> mappa2  # inalterata!
{'Estuario della Malasorte': ['murene', 'pesci tigre'],
 'Fossa del Naufragio': ['orche assassine'],
 'Lago dei Disperati': ["vortici d'acqua"],
 'Mare della Burrasca': ['polipi giganti']}
Mostra soluzione
[45]:

mappa1 = { "Baia dello Squalo" : ["squali"], "Estuario della Malasorte" : ["coccodrilli", "piraña"], "Mare della Burrasca" : ["barracuda", "meduse"], } mappa2 = { "Estuario della Malasorte" : ["murene", "pesci tigre"], "Mare della Burrasca" : ["polipi giganti"], "Fossa del Naufragio" : ["orche assassine"], "Lago dei Disperati" : ["vortici d'acqua"], } luogo1, luogo2 = "Estuario della Malasorte", "Mare della Burrasca" # scrivi qui

Uguaglianza

Possiamo verificare se due dizionari sono uguali con l’operatore di uguaglianza ==, che dati due dizionari ritorna True se contengono coppie chiave/valore uguali oppure False altrimenti:

[46]:
{'a':3, 'b':4} == {'a':3, 'b':4}
[46]:
True
[47]:
{'a':3, 'b':4} == {'c':3, 'b':4}
[47]:
False
[48]:
{'a':3, 'b':4} == {'a':3, 'b':999}
[48]:
False

Possiamo verificare l’uguaglianza di dizionari con numero di elementi diverso:

[49]:
{'a':3, 'b':4} == {'a':3}
[49]:
False
[50]:
{'a':3, 'b':4} == {'a':3,'b':3,'c':5}
[50]:
False

… e con elementi eterogenei:

[51]:
{'a':3, 'b':4} == {2:('q','p'), 'b':[99,77]}
[51]:
False

Uguaglianza e ordine

Dalla definizione:

  • Le chiavi sono immutabili, non hanno ordine e non vi possono essere duplicati

Visto che l’ordine non ha importanza, dizionari creati inserendo le stesse coppie chiavi/valore ma in ordine diverso saranno considerati uguali.

Esempio con creazione diretta:

[52]:
{'a':5, 'b':7} == {'b':7, 'a':5}
[52]:
True

Esempio con aggiunta graduale:

[53]:
diz1 = {}
diz1['a'] = 5
diz1['b'] = 7

diz2 = {}
diz2['b'] = 7
diz2['a'] = 5

print(diz1 == diz2)
True

DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. {1:2} == {2:1}
    
  2. {1:2,3:4} == {3:4,1:2}
    
  3. {'a'.upper():3} == {'a':3}
    
  4. {'A'.lower():3} == {'a':3}
    
  5. {'a': {1:2} == {3:4}}
    
  6. diz1 = {}
    diz1[2] = 5
    diz1[3] = 7
    
    diz2 = {}
    diz2[3] = 7
    diz2[2] = 5
    print(diz1 == diz2)
    
  7. diz1 = {'a':3,'b':8}
    diz2 = diz1
    diz1['a'] = 7
    print(diz1 == diz2)
    
  8. diz1 = {}
    diz1['a']=3
    diz2 = diz1
    diz2['a']=4
    print(diz1 == diz2)
    
  9. diz1 = {'a':3, 'b':4, 'c':5}
    diz2 = {'a':3,'c':5}
    del diz1['a']
    print(diz1 == diz2)
    
  10. diz1 = {}
    diz2 = {'a':3}
    diz1['a'] = 3
    diz1['b'] = 5
    diz2['b'] = 5
    print(diz1 == diz2)
    

Uguaglianza e copie

Quando si duplicano contenitori che contengono oggetti mutabili, se non si presta attenzione si possono ottenere sorprese. Ritorniamo quindi sull’argomento copie di dizionari superficiale e in profondità, questa volta cercando di verificare l’effettiva uguaglianza con Python.

ATTENZIONE: Per comprendere quanto segue, è necessario (ri)guardare bene il foglio dizionari 1 - Copiare un dizionario

DOMANDA: Vediamo un esempio semplice, con una copia ‘manuale’. Se esegui il seguente codice in Python Tutor, cosa stamperà? Quante regioni di memoria vedrai?

diz1 = {'a':3,
        'b':8}
diz2 = {'a':diz1['a'],
        'b':diz1['b'] }
diz1['a'] = 6

print('uguali?', diz1 == diz2)
print('diz1=', diz1)
print('diz2=', diz2)

NOTA: tutti i valori (3 e 8) sono immutabili.

Mostra risposta
[54]:
diz1 = {'a':3,
        'b':8}
diz2 = {'a':diz1['a'],
        'b':diz1['b'] }
diz1['a'] = 6

print('uguali?', diz1 == diz2)
print('diz1=', diz1)
print('diz2=', diz2)

jupman.pytut()
uguali? False
diz1= {'a': 6, 'b': 8}
diz2= {'a': 3, 'b': 8}
[54]:
Python Tutor visualization

DOMANDA: Se esegui il seguente codice in Python Tutor, cosa stamperà?

  1. Che tipo di copia abbiamo fatto? Superficiale? In profondità? (o tutte e due..?)

  2. Quante regioni di memoria vedrai?

diz1 = {'a':3,
        'b':8}
diz2 = dict(diz1)
diz1['a'] = 7

print('uguali?', diz1 == diz2)
print('diz1=', diz1)
print('diz2=', diz2)
Mostra risposta
[55]:
diz1 = {'a':3,
        'b':8}
diz2 = dict(diz1)
diz1['a'] = 7

print('uguali?', diz1 == diz2)
print('diz1=', diz1)
print('diz2=', diz2)

jupman.pytut()
uguali? False
diz1= {'a': 7, 'b': 8}
diz2= {'a': 3, 'b': 8}
[55]:
Python Tutor visualization

DOMANDA: Se esegui il seguente codice in Python Tutor, cosa stamperà?

  1. Che tipo di copia abbiamo fatto? Superficiale? In profondità? (o tutte e due..?)

  2. Quante regioni di memoria vedrai?

NOTA: i valori sono liste, perciò mutabili

diz1 = {'a':[1,2],
        'b':[4,5,6]}
diz2 = dict(diz1)
diz1['a'].append(3)

print('uguali?', diz1 == diz2)
print('diz1=', diz1)
print('diz2=', diz2)
Mostra risposta
[56]:
diz1 = {'a':[1,2],
        'b':[4,5,6]}
diz2 = dict(diz1)
diz1['a'].append(3)

print('uguali?', diz1 == diz2)
print('diz1=', diz1)
print('diz2=', diz2)

jupman.pytut()
uguali? True
diz1= {'a': [1, 2, 3], 'b': [4, 5, 6]}
diz2= {'a': [1, 2, 3], 'b': [4, 5, 6]}
[56]:
Python Tutor visualization

DOMANDA: Se esegui il seguente codice in Python Tutor, cosa stamperà?

  1. Che tipo di copia abbiamo fatto? Superficiale? In profondità? (o tutte e due..?)

  2. Quante regioni di memoria vedrai?

NOTA: i valori sono liste, perciò mutabili

import copy
diz1 = {'a':[1,2],
        'b':[4,5,6]}
diz2 = copy.deepcopy(diz1)
diz1['a'].append(3)

print('uguali?', diz1 == diz2)
print('diz1=', diz1)
print('diz2=', diz2)
Mostra risposta
[57]:
import copy
diz1 = {'a':[1,2],
        'b':[4,5,6]}
diz2 = copy.deepcopy(diz1)
diz1['a'].append(3)

print('uguali?', diz1 == diz2)
print('diz1=', diz1)
print('diz2=', diz2)

jupman.pytut()
uguali? False
diz1= {'a': [1, 2, 3], 'b': [4, 5, 6]}
diz2= {'a': [1, 2], 'b': [4, 5, 6]}
[57]:
Python Tutor visualization

DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. diz1 = {'a':[4,5],
            'b':[6,7]}
    diz2 = dict(diz1)
    diz2['a'] = diz1['b']
    diz2['b'][0] = 9
    print(diz1 == diz2)
    print(diz1)
    print(diz2)
    
  2. da = {'a':['x','y','z']}
    db = dict(da)
    db['a'] = ['w','t']
    dc = dict(db)
    print(da)
    print(db)
    print(dc)
    
  3. import copy
    
    la = ['x','y','z']
    diz1 = {'a':la,
            'b':la }
    diz2 = copy.deepcopy(diz1)
    diz2['a'][0] = 'w'
    print('uguali?', diz1 == diz2)
    print('diz1=', diz1)
    print('diz2=', diz2)
    

Esercizio - Zoom Doom

Scrivi del codice che data una stringa s (es 'ZOOM'), crea un dizionario diz ed assegna alle chiavi 'a', 'b' e 'c' la stessa identica lista contenente i caratteri della stringa come elementi (es ['Z','O','O','M']).

  • in Python Tutor dovrai vedere 3 frecce che dalle chiavi puntano alla stessa identica regione di memoria

  • modificando la lista associata ad una chiave, dovresti vedere la modifica anche nei liste associate alle altre chiavi

  • il tuo codice deve funzionare per qualunque stringa s

Esempio - data:

s = 'ZOOM'

Dopo il tuo codice, deve risultare:

>>> print(diz)
{'a': ['Z', 'O', 'O', 'M']
 'b': ['Z', 'O', 'O', 'M'],
 'c': ['Z', 'O', 'O', 'M'],
}
>>> diz['a'][0] = 'D'
>>> print(diz)
{'a': ['D', 'O', 'O', 'M']
 'b': ['D', 'O', 'O', 'M'],
 'c': ['D', 'O', 'O', 'M'],
}
Mostra soluzione
[58]:

s = 'ZOOM' # scrivi qui

Prosegui

Prosegui con Dizionari 3 - metodi