Dizionari 2 - operatori

Scarica zip esercizi

Naviga file online

Per manipolare i dizionari vi sono diversi operatori:

Operatore

Ritorna

Descrizione

len(dict)

int

Ritorna il numero di chiavi

dict[chiave]

obj

Ritorna il valore associato alla chiave

dict[chiave] = valore

Aggiunge o modifica il valore associato ad una chiave

del dict[chiave]

Rimuove la coppia chiave/valore

chiave in dict

bool

Ritorna True se chiave è presente nel dizionario

==,!=

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.ipynb
    dictionaries5-sol.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. Gli esercizi sono graduati per difficoltà, da una stellina ✪ a quattro ✪✪✪✪

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


{'z': 7}

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]:
{'armadio': 'un mobile a ripiani',
 'divano': 'mobile per rilassarsi',
 'lampadario': 'un apparecchio di illuminazione',
 'sedia': 'un mobile per sedersi'}

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]:
{(7, 9): ['spaz', 'zatura'], 4: 'boh', 5.0: 'un float', 'bla': 3}

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]:
{'armadio': 'un mobile a ripiani',
 'lampadario': 'un apparecchio di illuminazione appeso al soffitto',
 'sedia': 'un mobile per sedersi'}

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]:
{'forchette': 20, 'pentole': 3}

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}
    

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:

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

Vediamo come è rappresentato in Python Tutor:

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

Se proviamo a scrivere l’espressione

[36]:
prestiti['Rita']
[36]:
['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

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

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

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

Rivediamo il tutto in Python Tutor:

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

jupman.pytut()
Dracula
[41]:

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
[42]:
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

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:

[43]:
{'a':3, 'b':4} == {'a':3, 'b':4}
[43]:
True
[44]:
{'a':3, 'b':4} == {'c':3, 'b':4}
[44]:
False
[45]:
{'a':3, 'b':4} == {'a':3, 'b':999}
[45]:
False

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

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

… e con elementi eterogenei:

[48]:
{'a':3, 'b':4} == {2:('q','p'), 'b':[99,77]}
[48]:
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:

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

Esempio con aggiunta graduale:

[50]:
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 = {}
    diz1['a']=3
    diz2 = diz1
    diz2['a']=4
    print(diz1 == diz2)
    
  10. diz1 = {'a':3, 'b':4, 'c':5}
    diz2 = {'a':3,'c':5}
    del diz1['a']
    print(diz1 == diz2)
    
  11. 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
[51]:
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= {'b': 8, 'a': 6}
diz2= {'b': 8, 'a': 3}
[51]:

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
[52]:
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= {'b': 8, 'a': 7}
diz2= {'b': 8, 'a': 3}
[52]:

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
[53]:
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= {'b': [4, 5, 6], 'a': [1, 2, 3]}
diz2= {'b': [4, 5, 6], 'a': [1, 2, 3]}
[53]:

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
[54]:
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= {'b': [4, 5, 6], 'a': [1, 2, 3]}
diz2= {'b': [4, 5, 6], 'a': [1, 2]}
[54]:

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
[55]:
s = 'ZOOM'

# scrivi qui


{'b': ['Z', 'O', 'O', 'M'], 'a': ['Z', 'O', 'O', 'M'], 'c': ['Z', 'O', 'O', 'M']}
{'b': ['D', 'O', 'O', 'M'], 'a': ['D', 'O', 'O', 'M'], 'c': ['D', 'O', 'O', 'M']}

Prosegui

Prosegui con Dizionari 3

[ ]: