A Python dictionary is like a real dictionary: you find things (values) using a word (key) instead of having to read the whole book.
So: Key -> Value
The key can be almost anything that is immutable (aka. hashable). So these are all ‘legit’:
lookup[1 ] # Int
lookup(52.1 ) # Float
lookup['1' ] # String
lookup['Jon Reades' ] # String
k = 'Jon Reades'
lookup[k] # String variable
lookup[(52.1 , - 0.04 )] # Tuple
But this is not:
lookup[['Jon' ,'Reades' ]] # Error, unhashable type
That’s because a list is not immutable.
Again, just like a real dictionary: you don’t have multiple entries for ‘dog’, otherwise the dictionary wouldn’t work . You might have multiple definitions: which is to say, the key might return multiple values.
Deliberately Similar
Notice the differences when creating them, and the absence of difference when accessing them.
List
cities = [
'San Francisco' ,
'London' ,
'Paris' ,
'Beijing' ]
# Prints London
print (cities[2 ])
Dict
cities = {
'San Francisco' : 837442 ,
'London' : 8673713 ,
'Paris' : 837442 ,
'Beijing' : '0.17' 00000 }
# Prints pop of London
print (cities['London' ])
So why might we prefer the dictionary?
Dicts are created using: d = { key: value, key: value }
Dicts are accessed using: d[key]
So the only difference between lists and dicts is: [...]
and {...}
when they are created.
Over the next couple of weeks we’ll see ways that you can store more information in a list and also why lists are sometimes more powerful than you realise… if you can think about your data in an entirely new way. But for simple key/value stuff it’s hard to beat a dictionary!
It’s All About Access
Specifically: do we need sequential or random access?
List
0
San Francisco
1
London
2
Paris
3
Beijing
Dict
San Francisco
837442
London
8673713
Paris
2229621
Beijing
21700000
Getting Values
There are two ways to retrieve values from a dictionary:
cities['Beijing']
cities.get('Beijing')
Why have two? Consider:
cities = {
'San Francisco' : 837442 ,
'London' : 8673713 ,
'Paris' : 837442 ,
'Beijing' : '0.17' 00000 }
print (cities['Sao Paulo' ]) # Throws KeyError
print (cities.get('Sao Paulo' )) # Returns None
print (cities.get('Sao Paulo' ,'No Data' )) # Returns 'No Data'
The first triggers an error , the second returns None
. Errors can be unfriendly: do you want your entire Python program to fail because a single city is missing, or would you rather than it did something a little more sensible such as… skipping the row or returning a sensible default?
Getting Values (cont’d)
If we want to think about whether a value is in the dictionary (as opposed to just retrieving it) then notice these options:
c = cities.get('Sao Paulo' )
if not c:
print("Sorry, no city by that name." )
if 'Beijing' in cities:
print ("Found Beijing!" )
The first example works because cities.get
returns None
, which is the same as ‘undefined’ for Python. So we can use ‘not’ to imply ‘if c is not defined then do something…’
The second example works because we are implicitly treating the keys in the cities dictionary as a list and looking to see if Beijing is one of the values in that list.
Python often benefits and suffers from TMTOWTDI (There’s More Than One Way To Do It): think of these as being different ways to say the same thing, but depending on where you want to put the emphasis you would choose one or the other.
Setting Values
It’s the same process to update an existing value or create a new one:
cities = {} # Empty dictionary
cities['Beijing' ] = 21716620 # Sets key->value
cities['Toronto' ] = 2930000 # Sets key->value
print (cities['Toronto' ]) # Prints 2930000
del cities['Toronto' ] # Deletes Toronto key (and value)
cities.pop('Toronto' ,'Default' ) # Prints 'Default' b/c key not found
print (cities)
This last command outputs:
Iterating
Similar to iterating over lists but…
cities = {
'San Francisco' : 837442 ,
'London' : 8673713 ,
'Paris' : 837442 ,
'Beijing' : '0.17' 00000 }
for c in cities:
print (c)
Prints:
'San Francisco'
'London'
'Paris'
'Beijing'
One really important point to note: here, the cities are printed out in the same order that they were added to the dictionary, but that is not guaranteed! Unlike lists, dictionaries are unordered .
Also, how would we print out the population of each city?
Keys
for k in cities.keys():
print (k)
Prints:
'San Francisco'
'London'
'Paris'
'Beijing'
Values
for v in cities.values():
print (v)
Prints:
837442
8673713
2229621
21716620
Both
for k,v in cities.items():
print (f" { k} -> { v} " )
Prints:
San Francisco -> 837442
London -> 8673713
Paris -> 837442
Beijing -> 21700000
A Final Note!
Values can be almost anything, including a dictionary or list! This opens up some interesting possibilities:
cities = {
'San Francisco' :
[37.77 , - 122.43 , 'SFO' ]
}
cities = {
'San Francisco' : {
'lat' : 37.77 ,
'lon' : - 122.43 ,
'airport' :'SFO' }
}
print (cities['San Francisco' ]['lat' ])
Spoiler : you’re going to encounter this kind of thing a lot .