Dictionaries 2 - operators
Download exercise zip
There are several operators to manipulate dictionaries:
Operator |
Syntax |
Return |
Description |
|---|---|---|---|
|
|
Retorn the number of keys |
|
dict |
obj |
Return the value associated to the key |
|
dict |
Adds or modify the value associated to the key |
||
|
Removes the key/value couple |
||
obj |
|
Return |
|
|
|
Checks whether two dictionaries are equal or different |
What to do
Unzip exercises zip in a folder, you should obtain something like this:
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
WARNING: to correctly visualize the notebook, it MUST be in an unzipped folder !
open Jupyter Notebook from that folder. Two things should open, first a console and then a browser. The browser should show a file list: navigate the list and open the notebook
dictionaries2.ipynbGo on reading the exercises file, sometimes you will find paragraphs marked Exercises which will ask to write Python commands in the following cells.
Shortcut keys:
to execute Python code inside a Jupyter cell, press
Control + Enterto execute Python code inside a Jupyter cell AND select next cell, press
Shift + Enterto execute Python code inside a Jupyter cell AND a create a new cell aftwerwards, press
Alt + EnterIf the notebooks look stuck, try to select
Kernel -> Restart
len
We can obtain the number of key/value associations in a dictionary by using the function len:
[2]:
len({'a':5,
'b':9,
'c':7
})
[2]:
3
[3]:
len({3:8,
1:3
})
[3]:
2
[4]:
len({})
[4]:
0
QUESTION: Look at the following expressions, and for each try guessing the result (or if it gives an error):
len(dict())
len({'a':{}})
len({(1,2):{3},(4,5):{6},(7,8):{9}})
len({1:2,1:2,2:4,2:4,3:6,3:6})
len({1:2,',':3,',':4,})
len(len({3:4,5:6}))
Reading a value
At the end of dictionaries definition, it is reported:
Given a key, we can find the corresponding value very fast
How can we specify the key to search? It’s sufficient to use square brackets [ ], a bit like we already did for lists:
[5]:
furniture = {
'chair' : 'a piece of furniture to sit on',
'cupboard' : 'a cabinet for storage',
'lamp' : 'a device to provide illumination'
}
[6]:
furniture['chair']
[6]:
'a piece of furniture to sit on'
[7]:
furniture['lamp']
[7]:
'a device to provide illumination'
WARNING: What we put in square parenthesis must be a key present in the dictionary
If we put keys which are not present, we will get an error:
>>> furniture['armchair']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-19-ee891f51417b> in <module>
----> 1 furniture['armchair']
KeyError: 'armchair'
Fast disorder
Whenever we give a key to Python, how fast is it in getting the corresponding value? Very fast, so much so the speed does not depend on the dictionary dimension. Whether it is small or huge, given a key it will always find the associated value in about the same time.
When we hold a dictionary in real life, we typically have an item to search for and we turn pages until we get what we’re looking for: the fact items are sorted allows us to rapidly find the item.
We might expect the same also in Python, but if we look at the definition we find a notable difference:
Dictionaries are mutable containers which allow us to rapidly associate elements called keys to some values
Keys are immutable, don’t have order and there cannot be duplicates Values can be duplicated
If keys are not ordered, how can Python get the values so fast? The speed stems from the way Python memorizes keys, which is based on hashes, similarly for what happens with sets. The downside is we can only immutable objects as keys.
QUESTION: If we wanted to print the value 'a device to provide illumination' we see at the bottom of the dictionary, without knowing it corresponds to lamp, would it make sense to write something like this?
furniture = {'chair':'a piece of furniture to sit on',
'cupboard':'a cabinet for storage',
'lamp': 'a device to provide illumination'
}
print( furniture[2] )
QUESTION: Look at the following expressions, and for each try guessing which result it produces (or if it gives an error):
kabbalah = {
1 : 'Progress',
3 : 'Love',
5 : 'Creation'
}
kabbalah[0]
kabbalah[1]
kabbalah[2]
kabbalah[3]
kabbalah[4]
kabbalah[5]
kabbalah[-1]
QUESTION: Look at the following code fragments, and for each try guessing which result it produces (or if it gives an error):
{'a':4,'b':5}('a')
{1:2,2:3,3:4}[2]
{'a':1,'b':2}['c']
{'a':1,'b':2}[a]
{'a':1,'b':2}[1]
{'a':1,'b':2,'c':3}['c']
{'a':1,'b':2,'c':3}[len(['a','b','c'])]
{(3,4):(1,2)}[(1,2)]
{(1,2):(3,4)}[(1,2)]
{[1,2]:[3,4]}[[1,2]]
{'a','b','c'}['a']
{'a:b','c:d'}['c']
{'a':4,'b':5}{'a'}
d1 = {'a':'b'} d2 = {'b':'c'} print(d1[d2['c']])
d1 = {'a':'b'} d2 = {'b':'c'} print(d2[d1['a']])
{}[]{[]:3}[[]]
{1:7}['1']
{'':7}"[]"
{'':7}[""]
{"":7}['']
{'"':()}['']
{():7}[()]
{(()):7}[()]
{(()):7}[((),)]
Exercise - z7
✪ Given a dictionary d1 with keys 'b' and 'c' and integer values, create a dictionary d2 containing the key 'z' and associate to it the sum of values of keys from d1
your code must work for any
d1with keys'b'and'c'
Example - given:
d1 = {'a':6, 'b':2,'c':5}
After your code, it must result:
>>> print(d2)
{'z': 7}
[8]:
d1 = {'a':6, 'b':2,'c':5}
# write here
Writing in the dictionary
Can we write in a dictionary?
Dictionaries are mutable containers which allow us to rapidly associate elements called keys to some values
The definition talks about mutability, so we are allowed to modify dictionaries after creation.
Dictionaries are collections of key/value couples, and among the possible modifications we find:
adding a key/value couple
associate an existing key to a different value
remove a key/value couple
Writing - adding key/value
Suppose we created our dictionary furniture:
[9]:
furniture = {
'chair' : 'a piece of furniture to sit on',
'cupboard' : 'a cabinet for storage',
'lamp' : 'a device to provide illumination'
}
and afterwards we want to add a definition for 'armchair'. We can reuse the variable furniture followed by square brackets with inside the key we want to add ['armchair'] and after the brackets we will put an equality sign =
[10]:
furniture['armchair'] = 'a chair with armrests'
Note Jupyter didn’t show results, because the previous operation is an assignment command (only expressions generate results).
But something did actually happen in memory, we can check it by furniture:
[11]:
furniture
[11]:
{'chair': 'a piece of furniture to sit on',
'cupboard': 'a cabinet for storage',
'lamp': 'a device to provide illumination',
'armchair': 'a chair with armrests'}
Note the dictionary associated to the variable furniture was MODIFIED with the addition of 'armchair'.
When we add a key/value couple, we can use heterogenous types:
[12]:
trashcan = {
'bla' : 3,
4 : 'boh',
(7,9) : ['gar','bage']
}
[13]:
trashcan[5.0] = 'a float'
[14]:
trashcan
[14]:
{'bla': 3, 4: 'boh', (7, 9): ['gar', 'bage'], 5.0: 'a float'}
We are subject to the same constraints on keys we have during the creation, so we can only use immutable keys. If we try inserting a mutable type, for example a list, we will get an error:
>>> trashcan[ ['some', 'list'] ] = 8
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-51-195ac9c21bcd> in <module>
----> 1 trashcan[ ['some', 'list'] ] = 8
TypeError: unhashable type: 'list'
QUESTION: Look at the following expressions, and for each try guessing the result (or if gives an error):
d = {1:'a'} d[2] = 'a' print(d)
d = {} print(len(d)) d['a'] = 'b' print(len(d))
d1 = {'a':3, 'b':4} diz2 = diz1 diz1['a'] = 5 print(diz1) print(diz2)
diz1 = {'a':3, 'b':4} diz2 = dict(diz1) diz1['a'] = 5 print(diz1) print(diz2)
la = ['a','c'] diz = {'a':3, 'b':4, 'c':5} diz['d'] = diz[la[0]] + diz[la[1]] print(diz)
diz = {} diz[()]: '' diz[('a',)]: 'A' diz[('a','b')]: 'AB' print(diz)
la = [5,8,6,9] diz = {} diz[la[0]]=la[2] diz[la[2]]=la[0] print(diz)
diz = {} diz[(4,5,6)[2]] = 'c' diz[(4,5,6)[1]] = 'b' diz[(4,5,6)[0]] = 'a' print(diz)
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)
Writing - reassociate a key
Let’s suppose to change the definition of a lamp:
[15]:
furniture = {'chair':'a piece of furniture to sit on',
'cupboard':'a cabinet for storage',
'lamp': 'a device to provide illumination'
}
[16]:
furniture['lamp'] = 'a device to provide visible light from electric current'
[17]:
furniture
[17]:
{'chair': 'a piece of furniture to sit on',
'cupboard': 'a cabinet for storage',
'lamp': 'a device to provide visible light from electric current'}
Exercise - workshop
✪ MODIFY the dictionary workshop:
set the
'bolts'key value equal to the value of the'pincers'keyincrement the value of
wheelskey of1
your code must work with any number associated to the keys
DO NOT create new dictionaries, so no lines beginning with
workshop = {
Example - given:
workshop = {'wheels':3,
'bolts':2,
'pincers':5}
after your code, you should obtain:
>>> print(workshop)
{'bolts': 5, 'wheels': 4, 'pincers': 5}
[18]:
workshop = {'wheels' : 3,
'bolts' : 2,
'pincers': 5}
# write here
QUESTION: Look at the following code fragments expressions, and for each try guessing the result it produces (or if it gives an error):
diz = {'a':'b'} diz['a'] = 'a' print(diz)
diz = {'1':'2'} diz[1] = diz[1] + 5 # nasty print(diz)
diz = {1:2} diz[1] = diz[1] + 5 print(diz)
d1 = {1:2} d2 = {2:3} d1[1] = d2[d1[1]] print(d1)
Writing - deleting
To remove a key/value couple the special command del is provided. Let’s take a dictionary:
[19]:
kitchen = {
'pots' : 3,
'pans' : 7,
'forks' : 20
}
If we want to eliminate the couple pans : 7, we will write del followed by the name of the dictionary and the key to eliminate among square brackets:
[20]:
del kitchen['pans']
[21]:
kitchen
[21]:
{'pots': 3, 'forks': 20}
Trying to delete a non-existemt key will produce an error:
>>> del cucina['crankshaft']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-34-c0d541348698> in <module>
----> 1 del cucina['crankshaft']
KeyError: 'crankshaft'
QUESTION: Look at the following code fragments, and for each try guessing which result it produces (or if it gives an error):
diz = {'a':'b'} del diz['b'] print(diz)
diz = {'a':'b', 'c':'d'} del diz['a'] print(diz)
diz = {'a':'b', 'c':'d'} del diz['a'] del diz['a'] print(diz)
diz = {'a':'b'} new_diz = del diz['a'] print(diz) print(new_diz)
diz1 = {'a':'b', 'c':'d'} diz2 = diz1 del diz1['a'] print(diz1) print(diz2)
diz1 = {'a':'b', 'c':'d'} diz2 = dict(diz1) del diz1['a'] print(diz1) print(diz2)
diz = {'a':'b'} del diz['c'] print(diz)
diz = {'a':'b'} diz.del('a') print(diz)
diz = {'a':'b'} diz['a'] = None print(diz)
Exercise - desktop
Given a dictionary desktop:
desktop = {
'paper' :5,
'pencils':2,
'pens' :3
}
write some code which MODIFIES it so that after executing your code, the dictionary appears like this:
>>> print(desktop)
{'pencil sharpeners': 1, 'paper': 5, 'pencils': 2, 'papers': 4}
DO NOT write lines which begin with
desktop =
[22]:
desktop = {
'paper' :5,
'pencils':2,
'pens' :3
}
# write here
Exercise - garden
You have a dictionary garden which associates the names of present objects and their quantity. You are given:
a list
to_removecontaining the names of exactly two objects to eliminatea dictionary
to_addcontaining exactly two names of flowers associated to their quantity to add
MODIFY the dictionary garden according to the quantities given in to_remove (deleting the keys) and to_add (increasing the corresponding values)
assume that
gardenalways contains the objects given into_removeandto_addassume that
to_addalways and only containstulipsandroses
Example - given:
to_remove = ['weeds', 'litter']
to_add = { 'tulips': 4,
'roses' : 2
}
garden = { 'sunflowers': 3,
'tulips' : 7,
'weeds' : 10,
'roses' : 5,
'litter' : 6,
}
after your code, it must result:
>>> print(garden)
{'roses': 7, 'tulips': 11, 'sunflowers': 3}
[23]:
to_remove = ['weeds', 'litter']
to_add = { 'tulips': 4,
'roses' : 2
}
garden = { 'sunflowers': 3,
'tulips' : 7,
'weeds' : 10,
'roses' : 5,
'litter' : 6,
}
# write here
Exercise - translations
Given two dictionaries en_it and it_es of English-Italian and Italian-Spanish translations, write some code which MODIFIES a third dictionary en_es by placing translations from English to Spanish
assume that
en_italways and only contains translations ofhelloandroadassume that
it_esalways and only contains translations ofciaoandstradain the solution, ONLY use the constants
'hello'and'road', you will take the others you need from the dictionariesDO NOT create a new dictionary - so no lines beginning with
en_es = {
Example - given:
en_it = {
'hello' : 'ciao',
'road' : 'strada'
}
it_es = {
'ciao' : 'hola',
'strada' : 'carretera'
}
en_es = {}
after your code, it must print:
>>> print(en_es)
{'hello': 'hola', 'road': 'carretera'}
[24]:
en_it = {
'hello' : 'ciao',
'road' : 'strada'
}
it_es = {
'ciao' : 'hola',
'strada' : 'carretera'
}
en_es = {}
# write here
Membership with in
We can check whether a key is present in a dictionary by using the operator 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
WARNING: in searches among the keys, not in values!
[28]:
5 in {'a':5,'b':7}
[28]:
False
As always when dealing with keys, we cannot search for a mutable object, like for example lists:
>>> [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
It is possible to check for non belonging with the not in operator:
[29]:
'z' not in {'a':5,'b':7}
[29]:
True
[30]:
'a' not in {'a':5,'b':7}
[30]:
False
Equivalently, we can use this other form:
[31]:
not 'z' in {'a':5,'b':7}
[31]:
True
[32]:
not 'a' in {'a':5,'b':7}
[32]:
False
QUESTION: Look at the following expressions, and for each try guessing the result (or if it gives an error):
('a') in {'a':5}
('a','b') in {('a','b'):5}
('a','b',) in {('a','b'):5}
['a','b'] in {('a','b'):5}
{3: 'q' in {'q':5}}
{'q' not in {'q':0} : 'q' in {'q':0}}
{'a' in 'b'}
{'a' not in {'b':'a'}}
len({'a':6,'b':4}) in {1:2}
'ab' in {('a','b'): 'ab'}
None in {}
None in {'None':3}
None in {None:3}
not None in {0:None}
Exercise - The Helmsman
The restaurant “The Helmsman” serves a menu with exactly 3 courses each coupled with a side dish. The courses and the side dishes are numbered from 1 to 12. There are many international clients who don’t speak well the local language, so they often simply point a course number. They never point a side dish. Once the order is received, the waiter with a tablet verifies whether the course is ready with the correct side dish. Write some code which given an index of a course
shows True if this is in the kitchen coupled with the course, False otherwise.
DO NOT use
ifDO NOT use loops nor list comprehensions
HINT: if you don’t know how to do it, look at Booleans - Evaluation order
Example 1 - given:
# 1 2 3 4 5 6
menu = ['herring','butter','orata','salad', 'salmon', 'potatoes',
# 7 8 9 10 11 12
'tuna', 'beans', 'salmon', 'lemon', 'herring', 'salad']
kitchen = {'orata':'salad',
'salmon':'potatoes',
'herring':'salad',
'tuna':'beans'}
order = 1
The program will show False, because there is no association "herring" : "butter" in kitchen
Example 2 - given:
order = 3
the program will show True because there is the association "orata" : "salad" in cambusa
[33]:
order = 1 # False
#order = 3 # True
#order = 5 # True
#order = 7 # True
#order = 9 # False
#order = 11 # True
# 1 2 3 4 5 6
menu = ['herring','butter','orata','salad', 'salmon', 'potatoes',
# 7 8 9 10 11 12
'tuna', 'beans', 'salmon', 'lemon', 'herring', 'salad']
kitchen = {'orata':'salad',
'salmon':'potatoes',
'herring':'salad',
'tuna':'beans'}
# write here
Dictionaries of sequences
So far we almost always associated a single value to keys. What if wanted to associate more? For example, suppose we are in a library and we want to associate users with the books they borrowed. We could represent everything as a dictionary where a list of borrowed books is associated to each customer:
[34]:
loans = {'Marco': ['Les Misérables', 'Ulysses'],
'Gloria': ['War and Peace'],
'Rita': ['The Shining','Dracula','1984']}
Let’s see how it gets represented in Python Tutor:
[35]:
# WARNING: FOR PYTHON TUTOR TO WORK, REMEMBER TO EXECUTE THIS CELL with Shift+Enter
# (it's sufficient to execute it only once)
import jupman
[36]:
loans = {'Marco': ['Les Misérables', 'Ulysses'],
'Gloria': ['War and Peace'],
'Rita': ['The Shining','Dracula','1984']}
jupman.pytut()
[36]:
If we try writing the expression:
[37]:
loans['Rita']
[37]:
['The Shining', 'Dracula', '1984']
Python shows the corresponding list: for all intents and purposes Python considers loans['Rita'] as if it were a list, and we can use it as such. For example, if we wanted to access the 1-indexed book of the list, we would write [1] after the expression:
[38]:
loans['Rita'][1]
[38]:
'Dracula'
Equivalently, we might also save a pointer to the list by assigning the expression to a variable:
[39]:
ritas_list = loans['Rita']
[40]:
ritas_list
[40]:
['The Shining', 'Dracula', '1984']
[41]:
ritas_list[1]
[41]:
'Dracula'
Let’s see everything in Python Tutor:
[42]:
loans = {'Marco': ['Les Misérables', 'Ulysses'],
'Gloria': ['War and Peace'],
'Rita': ['The Shining','Dracula','1984']}
ritas_list = loans['Rita']
print(ritas_list[1])
jupman.pytut()
Dracula
[42]:
If you execute the code in Python Tutor, you will notice that as soon as we assign ritas_list, the corresponding list appears to ‘detach’ from the dictionary. This is only a graphical effect caused by Python Tutor, but from the point of view of the dictionary nothing changed. The intention is to show the list now is reachable both from the dictionary and from the new variable ritas_list.
Exercise - loans
Write some code to extract and print:
The first book borrowed by Gloria (
'War and Peace') and the last one borrowed by Rita ('1984')The number of books borrowed by Rita
Trueif everybody among Marco, Gloria and Rita borrowed at least a book,Falseotherwise
[43]:
loans = {'Marco': ['Les Misérables', 'Ulysses'],
'Gloria': ['War and Peace'],
'Rita': ['The Shining','Dracula','1984']}
# write here
1. The first book borrowed by Gloria is War and Peace
The last book borrowed by Rita is 1984
2. Rita borrowed 3 book(s)
3. Have everybody borrowed at least a book? True
Exercise - Shark Bay
The West India Company asked you to explore the tropical seas, which are known fo rthe dangerous species which live in their waters. You are provided with a dmap which associates places to species found therein:
dmap = {
"Shark Bay" : ["sharks"],
"Estuary of Bad Luck" : ["crocodiles", "piraña"],
"Shipwreck Trench" : ["killer whales", "tiger fishes"],
}
You are also given vague directions about how to update the dmap, using these variables:
place = "Shipwreck Trench"
dangers = ["morays", "blue spotted octupus"]
travel = "Sunken Sails Offshore"
exploration = ["barracudas", "jellyfishes"]
Try writing some code which using the variables above (or data from the map itself) MODIFIES dmap so to obtain:
>>> dmap
{'Shark Bay' : ['sharks'],
'Estuary of Bad Luck' : ['crocodiles', 'piraña', 'jellyfishes'],
'Shipwreck Trench' : ['killer whales', 'tiger fishes'],
'Jellyfishes Offshore': ['barracudas', 'jellyfishes', 'crocodiles', 'piraña']}
IMPORTANT: DO NOT use constant strings in your code (so no
"Shipwreck Trench"…). Numerical constants are instead allowed.
[44]:
place = "Estuary of Bad Luck"
dangers = ["morays", "blue spotted octupus"]
travel = "Sunken Sails Offshore"
exploration = ["barracudas", "jellyfishes"]
dmap = {
"Shark Bay" : ["sharks"],
"Estuary of Bad Luck": ["crocodiles", "piraña"],
"Shipwreck Trench" : ["killer whales", "tiger fishes"],
}
# write here
Exercise - The Storm Sea
The West India Company asks you now to produce a new map starting from dmap1 and dmap2. The new map must contain all the items from dmap1, expanded with the items from place1 and place2.
assume the items
place1andplace2are always present indmap1anddmap2.IMPORTANT: the execution of your code must not change
dmap1nordmap2
Example - given:
dmap1 = {
"Shark Bay" : ["sharks"],
"Estuary of Bad Luck" : ["crocodiles", "piraña"],
"Storm Sea" : ["barracudas", "morays"]
}
dmap2 = {
"Estuary of Bad Luck" : ["morays", "shark fishes"],
"Storm Sea" : ["giant octupses"],
"Shipwreck Trench" : ["killer whales"],
"Lake of the Hopeless" : ["water vortexes"]
}
place1, place2 = "Estuary of Bad Luck", "Storm Sea"
After your code, it must result:
>>> new
{'Estuary of Bad Luck': ['crocodiles', 'piraña', 'morays', 'shark fishes'],
'Shark Bay': ['sharks'],
'Storm Sea': ['barracudas', 'morays', 'giant octupses']}
>>> dmap1 # not changed
{'Estuary of Bad Luck': ['crocodiles', 'piraña'],
'Shark Bay': ['sharks'],
'Storm Sea': ['barracudas', 'morays']}
>>> dmap2 # not changed
{'Estuary of Bad Luck': ['morays', 'shark fishes'],
'Lake of the Hopeless': ['water vortexes'],
'Shipwreck Trench': ['killer whales'],
'Storm Sea': ['giant octupses']}
[45]:
dmap1 = {
"Shark Bay" : ["sharks"],
"Estuary of Bad Luck" : ["crocodiles", "piraña"],
"Storm Sea" : ["barracudas", "morays"]
}
dmap2 = {
"Estuary of Bad Luck" : ["morays", "shark fishes"],
"Storm Sea" : ["giant octupses"],
"Shipwreck Trench" : ["killer whales"],
"Lake of the Hopeless" : ["water vortexes"]
}
place1, place2 = "Estuary of Bad Luck", "Storm Sea"
# write here
Equality
We can verify whether two dictionaries are equal with == operator, which given two dictionaries return True if they contain kequal ey/value couples or False otherwise:
[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
We can verify equality of dictionaries with a different number of elements:
[49]:
{'a':3, 'b':4} == {'a':3}
[49]:
False
[50]:
{'a':3, 'b':4} == {'a':3,'b':3,'c':5}
[50]:
False
… and with heterogenous elements:
[51]:
{'a':3, 'b':4} == {2:('q','p'), 'b':[99,77]}
[51]:
False
Equality and order
From the definition:
Keys are immutable, don’t have order and there cannot be duplicates
Since order has no importance, dictionaries created by inserting the same key/value couples in a differenct order will be considered equal.
For example, let’s try direct creation:
[52]:
{'a':5, 'b':7} == {'b':7, 'a':5}
[52]:
True
What about incremental update?
[53]:
diz1 = {}
diz1['a'] = 5
diz1['b'] = 7
diz2 = {}
diz2['b'] = 7
diz2['a'] = 5
print(diz1 == diz2)
True
QUESTION: Look at the following code fragments, and for each try guessing which result it produces (or if it gives an error):
{1:2} == {2:1}
{1:2,3:4} == {3:4,1:2}
{'a'.upper():3} == {'a':3}
{'A'.lower():3} == {'a':3}
{'a': {1:2} == {3:4}}
diz1 = {} diz1[2] = 5 diz1[3] = 7 diz2 = {} diz2[3] = 7 diz2[2] = 5 print(diz1 == diz2)
diz1 = {'a':3,'b':8} diz2 = diz1 diz1['a'] = 7 print(diz1 == diz2)
diz1 = {} diz1['a']=3 diz2 = diz1 diz2['a']=4 print(diz1 == diz2)
diz1 = {'a':3, 'b':4, 'c':5} diz2 = {'a':3,'c':5} del diz1['a'] print(diz1 == diz2)
diz1 = {} diz2 = {'a':3} diz1['a'] = 3 diz1['b'] = 5 diz2['b'] = 5 print(diz1 == diz2)
Equality and copies
When duplicating containers which hold mutable objects, if we do not pay attention we might get surprises. Let’s go back on the topic of shallow and deep copies of dictionaries, this time trying to verify the effective equality in Python.
WARNING: Have you read Dictionaries 1 - Copying a dictionary ?
If not, do it now!
QUESTION: Let’s see a simple example, with a ‘manual’ copy. If you execute the following code in Python Tutor, what will it print? How many memory regions will you see?
d1 = {'a':3,
'b':8}
d2 = {'a':d1['a'],
'b':d1['b'] }
d1['a'] = 6
print('equal?', d1 == d2)
print('d1=', d1)
print('d2=', d2)
NOTE: all values (3 and 8) are immutable.
[54]:
d1 = {'a':3,
'b':8}
d2 = {'a':d1['a'],
'b':d1['b'] }
d1['a'] = 6
print('equal?', d1 == d2)
print('d1=', d1)
print('d2=', d2)
jupman.pytut()
equal? False
d1= {'a': 6, 'b': 8}
d2= {'a': 3, 'b': 8}
[54]:
QUESTION: If you execute the following code in Python Tutor, what will it print?
Which type of copy did we do? Shallow? Deep? (or both …?)
How many memory regions will you see?
d1 = {'a':3,
'b':8}
d2 = dict(d1)
d1['a'] = 7
print('equal?', d1 == d2)
print('d1=', d1)
print('d2=', d2)
[55]:
d1 = {'a':3,
'b':8}
d2 = dict(d1)
d1['a'] = 7
print('equal?', d1 == d2)
print('d1=', d1)
print('d2=', d2)
jupman.pytut()
equal? False
d1= {'a': 7, 'b': 8}
d2= {'a': 3, 'b': 8}
[55]:
QUESTION: If you execute the following code in Python Tutor, what will it print?
Which type of copy did we do? Shallow? Deep? (or both …?)
How many memory regions will you see?
NOTE: the values are lists, thus they are mutable
d1 = {'a':[1,2],
'b':[4,5,6]}
d2 = dict(d1)
d1['a'].append(3)
print('equal?', d1 == d2)
print('d1=', d1)
print('d2=', d2)
[56]:
d1 = {'a':[1,2],
'b':[4,5,6]}
d2 = dict(d1)
d1['a'].append(3)
print('equal?', d1 == d2)
print('d1=', d1)
print('d2=', d2)
jupman.pytut()
equal? True
d1= {'a': [1, 2, 3], 'b': [4, 5, 6]}
d2= {'a': [1, 2, 3], 'b': [4, 5, 6]}
[56]:
QUESTION: If you execute the following code in Python Tutor, what will it print?
Which type of copy did we do? Shallow? Deep? (or both …?)
How many memory regions will you see?
NOTE: the values are lists, so they are mutable
import copy
d1 = {'a':[1,2],
'b':[4,5,6]}
d2 = copy.deepcopy(d1)
d1['a'].append(3)
print('equal?', d1 == d2)
print('d1=', d1)
print('d2=', d2)
[57]:
import copy
d1 = {'a':[1,2],
'b':[4,5,6]}
d2 = copy.deepcopy(d1)
d1['a'].append(3)
print('equal?', d1 == d2)
print('d1=', d1)
print('d2=', d2)
jupman.pytut()
equal? False
d1= {'a': [1, 2, 3], 'b': [4, 5, 6]}
d2= {'a': [1, 2], 'b': [4, 5, 6]}
[57]:
QUESTION: Look at the following code fragments, and for each try guessing which result it produces (or if it gives an error):
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)
da = {'a':['x','y','z']} db = dict(da) db['a'] = ['w','t'] dc = dict(db) print(da) print(db) print(dc)
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)
Exercise - Zoom Doom
Write some code which given a string s (i.e. 'ZOOM'), creates a dictionary zd and assigns to keys 'a', 'b' and 'c' the same identical list containing the string characters as elements (i.e. ['Z','O','O','M']).
in Python Tutor you should see 3 arrows which go from keys to the same identical memory region
by modifying the list associated to each key, you should see the modification also in the lists associated to other keys
your code must work for any string
s
Example - given:
s = 'ZOOM'
After your code, it should result:
>>> print(zd)
{'a': ['Z', 'O', 'O', 'M']
'b': ['Z', 'O', 'O', 'M'],
'c': ['Z', 'O', 'O', 'M'],
}
>>> zd['a'][0] = 'D'
>>> print(zd)
{'a': ['D', 'O', 'O', 'M']
'b': ['D', 'O', 'O', 'M'],
'c': ['D', 'O', 'O', 'M'],
}
[58]:
s = 'ZOOM'
# write here
Continue
Go on reading Dictionaries 3 - methods
[ ]: