1. Reviewing Sequences

We have seen four kinds of sequences so far: strings, lists, ranges, and tuples.
Python can distinguish among them via their delimiters: quotes for strings, square brackets for lists, and parentheses for tuples.

In [1]:
phrase = "Quincy's quilters quit quilting quickly"     # a string
numbers = [0, 10, 20, 30, 40, 50]                      # a list of numbers
courses = ["CS 111", "CS 115", "CS 121"
           "CS 204", "CS 220", "CS 230"]               # a list of strings
person = ('Frederick', 'Douglass')                     # a tuple of strings
date = ('November', 8, 20201)                          # a mixed tuple
odds = range(1, 10, 2)                                 # a range of numbers
In [2]:
print("type of 'phrase':", type(phrase))
print("type of 'numbers':", type(numbers))
print("type of 'characters':", type(courses))
print("type of 'person':", type(person))
print("type of 'date':", type(date))
print("type of 'odds':", type(odds))
type of 'phrase': <class 'str'>
type of 'numbers': <class 'list'>
type of 'characters': <class 'list'>
type of 'person': <class 'tuple'>
type of 'date': <class 'tuple'>
type of 'odds': <class 'range'>

Common Operations for Sequences

Sequences share many operations:

  • subscripting with indices,
  • slicing (with colon),
  • checking for membership with in,
  • use of len to indicate length
  • iteration through loops

a) Examples of indexing
Outputs in this case are a single element of the sequence.

In [3]:
phrase[14] # access element at index 14
In [4]:
numbers[3] # access element at index 3
In [5]:
person[1]  # access element at index 1
In [6]:
odds[2] # access element at index 2

b) Examples of slicing
Outputs in this case are subsequences.

In [7]:
phrase[4:13] # slicing - get the elements indexed from 4 to 13 (this is not included)
"cy's quil"
In [8]:
date[:2] # slicing - get the first two elements of the tuple
('November', 8)
In [9]:
numbers[2:] # slicing - get all elements starting at index 2
[20, 30, 40, 50]
In [10]:
odds[1::2] # slicing - get every other odd number starting at index 1
range(3, 11, 4)

b) Examples of using the membership operator in
Outputs are boolean values.

In [11]:
2015 in date
In [12]:
50 in numbers
In [13]:
'quit' in phrase
In [14]:
4 in odds

Reminder: Why do we care about tuples?

Tuples are often used in Python to do multiple assignments in one single statement:

In [15]:
a, b = 0, 1
a, b
(0, 1)
In [16]:
0, 1
(0, 1)

Python generates tuples whenever we use commas to separate values:

In [17]:
len(phrase), len(numbers), len(courses), len(person), len(date), len(odds)
(39, 6, 5, 2, 3, 5)

2. Introducing Dictionaries

Dictionaries are unordered (see note below) collections that map keys to values:

In [18]:
daysOfMonth = {'Jan': 31, 'Feb': 28, 'Mar': 31, 'Apr': 30,
               'May': 31, 'Jun': 30, 'Jul': 31, 'Aug': 31,
               'Sep': 30, 'Oct': 31, 'Nov': 30} # one month is missing
{'Jan': 31,
 'Feb': 28,
 'Mar': 31,
 'Apr': 30,
 'May': 31,
 'Jun': 30,
 'Jul': 31,
 'Aug': 31,
 'Sep': 30,
 'Oct': 31,
 'Nov': 30}

Note: Dictionaries behind the scenes do actually maintain the order in which keys/values were inserted into the dictionary. This explains why, when we run the cell above, the months are outputted in the same order they were written. But you should not treat dictionaries as an ordered collection in the same way you would a sequence like a list. You cannot access a dictionary by index. You cannot append to a dictionary because a dictionary does not have a "last" item. Therefore, conceptually you should treat the key-value pairs as unordered elements in the dictionary.

3. Adding and Removing from Dictionaries

3.1 Literal dicts

We can write the entire dictionary as a literal value by wrapping braces around a comma-separate sequence of key:value pairs:

In [19]:
student = {'name': 'Georgia Dome', 'dorm': 'Munger Hall', 
           'section': 2, 
           'year': 2023, 
           'CSMajor?': True}

{'name': 'Georgia Dome',
 'dorm': 'Munger Hall',
 'section': 2,
 'year': 2023,
 'CSMajor?': True}
In [21]:
In [22]:
# a dictionary may have different types as keys and values
mixedLabelDict = {"orange": "fruit", 
                  3: "March", 
                  "even": [2,4,6,8]} 
{'orange': 'fruit', 3: 'March', 'even': [2, 4, 6, 8]}

3.2 Growing Dictionaries and Mutability

Dictionaries are mutable. This means we can start with an empty dictionary and grow it in much the same way we do a list. This is a common way to create dictionaries in many of our problems.

In [23]:
cart = {} # The empty dictionary
cart['oreos'] = 3.99
cart['kiwis'] = 2.54

{'oreos': 3.99, 'kiwis': 2.54}

Note: Since dictionaries are unordered, the order in which we enter key/value pairs is irrelevant.

Recall that the dictionary above was missing the month of december which has 31 days. Add that to the daysOfMonth dictionary below.

In [24]:
# Your code here
daysOfMonth['Dec'] = 31

3.3 The pop method

Given a key, the pop method on a dictionary removes the key/value pair with that key from the dictionary and returns the value formerly associated with the key. pop mutates the dictionary.

In [25]:
In [26]:
{'kiwis': 2.54}

QUESTION: It looks like the method pop works similarly to the one for lists. Do you think it will behave the same if we don't provide an argument value for it? Explain.

3.4 Accessing Dictionaries With The Subscripting Operator

We do this not with indices, but with keys.

In [27]:

IMPORTANT Note that we don't have to loop through the key/value pairs to find the value associated with the key. We just use the key as the subscript, and the dictionary "magically" returns the corresponding values. This is easy and powerful!

Trying to look for a key that doesn't exist...

In [28]:
KeyError                                  Traceback (most recent call last)
<ipython-input-28-66ac62b8a356> in <module>
----> 1 daysOfMonth['October']

KeyError: 'October'

Note: Indexing with 0, 1, ..., will not work, the same way 'October' didn't work, because subscription is based only on the keys.

In [29]:
KeyError                                  Traceback (most recent call last)
<ipython-input-29-dc45923b543c> in <module>
----> 1 daysOfMonth[0]

KeyError: 0

3.5 Check if a key exists with the operator in

The operator in can be used with dictionaries just like with sequence types.
We can check if a key is in a dictionary, by typing: key in someDict. However, this doesn't work with values.

In [30]:
'Oct' in daysOfMonth
In [31]:
31 in daysOfMonth
In [32]:
if 'October' in daysOfMonth:
    print("Key not found")
Key not found

Your Turn: Create a simple dictionary

  1. Define a dictionary named person that has two keys: 'first' and 'last' and as corresponding values your own first and last names.
  2. Use this dict in a print statement to display: Well done, FIRST LAST! (where FIRST and LAST are your first and last names read from the dictionary).
In [33]:
# create dict
# Your code here
person = {'first': 'Katherine', 'last': 'Johnson'}
In [34]:
# print phrase
# Your code here
print("Well done, " + person['first'], person['last'] + "!")
Well done, Katherine Johnson!

3.6 More examples of dictionaries

We''ll use these dictionaries in following examples in this notebook, so don't forget to run this cell.

In [35]:
student = {'name': 'Georgia Dome', 
           'dorm': 'Munger Hall', 
           'section': 2, 
           'year': 2023, 
           'CSMajor?': True}

phones = {'Gal Gadot': 5558671234, 
          'Trevor Noah': 9996541212, 
          'Paula A. Johnson': 7811234567}

computerScientists = {('Ada','Lovelace'):['ada@wellesley.edu', 1815],
                      ('Grace', 'Hopper'):['grace@wellesley.edu', 1906],
                      ('Margaret', 'Hamilton'):['margaret@wellesley.edu', 1936],
                      ('Katherine', 'Johnson'):['katherine@wellesley.edu', 1918]}

# these are contributions of edits by Wikipedia editors

contributions = {
                 'uma52': {2015: 10, 2016: 15},
                 'setam$3': {2012: 23, 2013: 34, 2014: 17},
                 'rid12': {2009: 5, 2010: 18, 2012: 4} 

The dictionary computerScientists contains four important women in the field of computer science. Check out their Wikipedia pages below to learn more about them:

  1. Ada Lovelace: One of the first programmers and credited with writing the first computer program.
  2. Grace Hopper: One of the pioneers of compilers (programs that translate one computer language to another) and the COBOL programming language.
  3. Margaret Hamilton): Her team developed the onboard flight software for the Apollo Missions and was director of the Software Engineering Division of the MIT Instrumentation Labratory.
  4. Katherine Johnson: An American Mathematician whose prowess in calculating orbital mechanics was essential in verifying calculations by early computers used in NASA flight missions. One of the first African American women to work as a NASA scientist.

President Barack Obama awarded all three American women the Presidential Medal of Freedom.

Your Turn: Subscripting dictionaries

In [36]:
{'name': 'Georgia Dome',
 'dorm': 'Munger Hall',
 'section': 2,
 'year': 2023,
 'CSMajor?': True}
In [37]:
# write the expression to retrieve the value 2023 from student
# Your code here
In [38]:
{'Gal Gadot': 5558671234,
 'Trevor Noah': 9996541212,
 'Paula A. Johnson': 7811234567}
In [39]:
# write the expression to retrive Gal Gadot's phone number from phones
# Your code here
phones['Gal Gadot']
In [40]:
{('Ada', 'Lovelace'): ['ada@wellesley.edu', 1815],
 ('Grace', 'Hopper'): ['grace@wellesley.edu', 1906],
 ('Margaret', 'Hamilton'): ['margaret@wellesley.edu', 1936],
 ('Katherine', 'Johnson'): ['katherine@wellesley.edu', 1918]}
In [41]:
# write the expression to retrieve Grace Hopper's information from computerScientists
# Your code here
computerScientists[('Grace', 'Hopper')]
['grace@wellesley.edu', 1906]
In [44]:
# what does this return?
computerScientists[('Ada', 'Lovelace')][0][0]

3.7 Changing key-value pairs in a dictionary

When a key is already in a dictionary, assigning a value to that key in the dictionary changes the value at that key.

For example, the key Feb is associated with what value in the daysOfMonth dictionary?

In [45]:
{'Jan': 31,
 'Feb': 28,
 'Mar': 31,
 'Apr': 30,
 'May': 31,
 'Jun': 30,
 'Jul': 31,
 'Aug': 31,
 'Sep': 30,
 'Oct': 31,
 'Nov': 30,
 'Dec': 31}
In [46]:

If it's a leap year, we can change the value associated with Feb to be 29 via assignment with the subscript:

In [47]:
daysOfMonth['Feb'] = 29   # change value associated with a key
In [48]:
{'Jan': 31,
 'Feb': 29,
 'Mar': 31,
 'Apr': 30,
 'May': 31,
 'Jun': 30,
 'Jul': 31,
 'Aug': 31,
 'Sep': 30,
 'Oct': 31,
 'Nov': 30,
 'Dec': 31}
In [49]:

3.8 Dictionary keys must be immutable

Although dictionaries are mutable, the keys of dictionaries must be immutable.

In [53]:
daysOfMonth[['Feb', 2021]] = 28   # try to use a key that has month and year in a list
TypeError                                 Traceback (most recent call last)
<ipython-input-53-692103ac9cdf> in <module>
----> 1 daysOfMonth[['Feb', 2021]] = 28   # try to use a key that has month and year in a list

TypeError: unhashable type: 'list'

But the following works, because a tuple is immutable:

In [55]:
daysOfMonth[('Feb', 2021)] = 28
{'Jan': 31,
 'Feb': 29,
 'Mar': 31,
 'Apr': 30,
 'May': 31,
 'Jun': 30,
 'Jul': 31,
 'Aug': 31,
 'Sep': 30,
 'Oct': 31,
 'Nov': 30,
 'Dec': 31,
 ('Feb', 2021): 28}

Reminder that you can remove keys using pop. But here we need to use the entire key as a tuple in order to remove it.

In [56]:
daysOfMonth.pop(('Feb', 2021))
In [57]:
{'Jan': 31,
 'Feb': 29,
 'Mar': 31,
 'Apr': 30,
 'May': 31,
 'Jun': 30,
 'Jul': 31,
 'Aug': 31,
 'Sep': 30,
 'Oct': 31,
 'Nov': 30,
 'Dec': 31}

The computerScientists dictionary is an example of a dictionary with tuples as keys.

In [58]:
{('Ada', 'Lovelace'): ['ada@wellesley.edu', 1815],
 ('Grace', 'Hopper'): ['grace@wellesley.edu', 1906],
 ('Margaret', 'Hamilton'): ['margaret@wellesley.edu', 1936],
 ('Katherine', 'Johnson'): ['katherine@wellesley.edu', 1918]}

4. Getting the keys and values

In [59]:
daysOfMonth # the entire dict
{'Jan': 31,
 'Feb': 29,
 'Mar': 31,
 'Apr': 30,
 'May': 31,
 'Jun': 30,
 'Jul': 31,
 'Aug': 31,
 'Sep': 30,
 'Oct': 31,
 'Nov': 30,
 'Dec': 31}

The methods keys, values, and items

Sometimes we are interested in knowing these parts of the dictionary. Each of these methods returns an object containing only the keys, values, and items, respectively.

In [60]:
dict_keys(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'])

Note that the order of elements in the list is not predictable.

In [61]:

Note that the .keys(), .values(), and .items() methods each return a different type of object.

In [62]:
dict_values([31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31])
In [63]:

The list returned by .values() is synchronized with the list returned by .keys(). You can find corresponding months and days in the same index.

In [64]:
dict_items([('Jan', 31), ('Feb', 29), ('Mar', 31), ('Apr', 30), ('May', 31), ('Jun', 30), ('Jul', 31), ('Aug', 31), ('Sep', 30), ('Oct', 31), ('Nov', 30), ('Dec', 31)])
In [65]:

The objects of type dict_keys, dict_values, and dict_items are so-called dictionary views that reflect any subsequent changes to the underlying dictionary from which they were made.

In [66]:
numNames = {'one': 1, 'two': 2, 'three': 3}
ks = numNames.keys() 
vs = numNames.values()
its = numNames.items()
print('keys:', ks)
print('values:', vs)
print('items:', its)
keys: dict_keys(['one', 'two', 'three'])
values: dict_values([1, 2, 3])
items: dict_items([('one', 1), ('two', 2), ('three', 3)])
In [67]:
numNames['four'] = 4
print('keys:', ks)
print('values:', vs)
print('items:', its)
keys: dict_keys(['one', 'two', 'three', 'four'])
values: dict_values([1, 2, 3, 4])
items: dict_items([('one', 1), ('two', 2), ('three', 3), ('four', 4)])
In [68]:
print('keys:', ks)
print('values:', vs)
print('items:', its)
keys: dict_keys(['two', 'three', 'four'])
values: dict_values([2, 3, 4])
items: dict_items([('two', 2), ('three', 3), ('four', 4)])

5. Iterating over a dictionary

There are many ways to iterate over a dictionary:

  1. over the keys (do not use .keys())
  2. over the values (with .values())
  3. over the items (with .items())
In [69]:
{'Gal Gadot': 5558671234,
 'Trevor Noah': 9996541212,
 'Paula A. Johnson': 7811234567}
In [70]:
# iterate directly (by default Python goes over the keys, because they are unique)
for key in phones:
    print(key, phones[key])
Gal Gadot 5558671234
Trevor Noah 9996541212
Paula A. Johnson 7811234567

Using for to iterate over a dictionary means iterating over all the keys in the dictionary, so there is no need to use .keys(), which would create an unnecessary object. So we prefer to write for key in phones: rather than for key in phones.keys():.

In [71]:
for key in phones:
    print(key, phones[key])
Gal Gadot 5558671234
Trevor Noah 9996541212
Paula A. Johnson 7811234567
In [72]:
for val in phones.values():
    print("Call " + str(val) + "!")
Call 5558671234!
Call 9996541212!
Call 7811234567!
In [74]:
# sometimes is useful to iterate over the items directly
# notice the tuple assignment in the for loop
for name, number in phones.items():
    print(f"Call {name} at {number}.")
Call Gal Gadot at 5558671234.
Call Trevor Noah at 9996541212.
Call Paula A. Johnson at 7811234567.

QUESTION: Can we go from values to keys, as we did from keys to values? What can we say about keys and values in a dictionary?

In [ ]:
daysOfMonth = {'Jan': 31, 'Feb': 28, 'Mar': 31, 'Apr': 30,
               'May': 31, 'Jun': 30, 'Jul': 31, 'Aug': 31,
               'Sep': 30, 'Oct': 31, 'Nov': 30, 'Dec': 31}
In [75]:
for month, days in daysOfMonth.items():
    print(f"{month} has {days} days.")
Jan has 31 days.
Feb has 29 days.
Mar has 31 days.
Apr has 30 days.
May has 31 days.
Jun has 30 days.
Jul has 31 days.
Aug has 31 days.
Sep has 30 days.
Oct has 31 days.
Nov has 30 days.
Dec has 31 days.

6. Exercise 1: rewrite scrabblePoints

A great use for dictionaries is to store data that can simplify choosing among different values. Here is a scrabblePoints function.

In [76]:
def scrabblePoints(letter):
    "Return the scrabble score associated with a letter."
    if letter in 'aeilnorstu':
        return 1
    elif letter in 'dg':
        return 2
    elif letter in 'bcmp':
        return 3
    elif letter in 'fhvwy':
        return 4
    elif letter in 'k':
        return 5
    elif letter in 'jx':
        return 8
    elif letter in 'qz':
        return 10
    return 0

for letter in 'abdhjkq': 
    print(f"{letter} is worth {scrabblePoints(letter)} points.")
a is worth 1 points.
b is worth 3 points.
d is worth 2 points.
h is worth 4 points.
j is worth 8 points.
k is worth 5 points.
q is worth 10 points.

We'll start by storing the letter and their points in a dictionary:

In [77]:
scrabbleDict = {'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 
                'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 
                'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 
                'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10}
In [78]:
def scrabblePoints2(letter):
    "Return the scrabble score associated with a letter."
    # Algorithm
    # 1. If letter is in scrabbleDict, return its points
    # 2. Otherwise return 0
    # Your code here
    if letter in scrabbleDict:
        return scrabbleDict[letter]
    return 0
In [79]:
# Test with different values
for letter in 'abdhjkq7!': 
    print(f"{letter} is worth, {scrabblePoints2(letter)} points.")
a is worth, 1 points.
b is worth, 3 points.
d is worth, 2 points.
h is worth, 4 points.
j is worth, 8 points.
k is worth, 5 points.
q is worth, 10 points.
7 is worth, 0 points.
! is worth, 0 points.

7. Exercise 2: Word Frequencies

In [80]:
def frequencies(wordList):
    """Given a list of words, returns a dictionary of word frequencies"""
    # Algorithm
    # 1. create an empty dict
    # 2. iterate through the words of the given list
    # 3. set the value or increment the value for each word
    # 4. return the dict
    # Your code here
    freqDict = {}
    for word in wordList:
        if word in freqDict:
            freqDict[word] += 1
            freqDict[word] = 1
    return freqDict
In [81]:
frequencies(["house", "bird", "house", "chirp", "feather", "chirp", "chirp"])
{'house': 2, 'bird': 1, 'chirp': 3, 'feather': 1}

8. Exercise 3: Find largest value

Write the function getKeyWithMaxValue that behaves as shown below:

In [2]: getKeyWithMaxValue({'A': 0.25, 'E': 0.36, 
                            'I': 0.16, 'O': 0.18, 'U': 0.05})

Out[2]: 'E'

Hint: Remember the built-in function max; when given a list, it returns the largest value in the list. Also, remember the method values for a dictionary.

In [82]:
def getKeyWithMaxValue(dct):
    """Given a dict whose values are numbers, return the key that
    corresponds to the highest value.
    # One possible algorithm:
    # 1. find the max with the help of the .values method
    # 2. iterate through the keys to find which key has a value that is equal to max
    # 3. return that key (it can be an early return)
    # Your code here
    maxVal = max(dct.values())
    for letter in dct:
        if dct[letter] == maxVal:
            return letter
In [83]:
getKeyWithMaxValue({'A': 0.25, 'E': 0.36, 'I': 0.16, 'O': 0.18, 'U': 0.05})

9. Exercise 4: Reverse Lookup

Write a function that takes a dict that has many similar values and creates a new dict where the keys are the unique values and the values are lists of the keys.


In [30]: results = {'Andy': 'bronze', 'Carolyn': 'gold', 'Peter': 'bronze', 'Sohie': 'silver'}
In [30]: reverseDictionary(results)
Out[31]: {'bronze': ['Andy', 'Peter'], 'gold': ['Carolyn'], 'silver': ['Sohie']}
In [84]:
def reverseDictionary(dct):
    """Given a dict that has many repeating values, returns a new dict where 
    the old values become the new keys.  The new values are lists containing
    all the old keys with the same value.
    # Algorithm
    # 1. Create an empty dict
    # 2. Iterate over the dictionary
    # 3. If a key exists, append to the corresponding value (which is a list)
    # 4. If not, create the key:value pair, by assigning a list with one element to the new key
    # 5. return dict
    # Your code here
    reverseDct = {}
    for key, value in dct.items():
        if value in reverseDct:
            reverseDct[value] = [key]
    return reverseDct
In [85]:
results = {'Andy': 'bronze', 'Carolyn': 'gold', 'Peter': 'bronze', 'Sohie': 'silver'}

{'bronze': ['Andy', 'Peter'], 'gold': ['Carolyn'], 'silver': ['Sohie']}

10. Exercise 5: reverse dictionary (month lengths)

How can you create the dictionary monthLengths with one single line of code?

monthLengths = {31: ['Jan','Mar','May','Jul','Aug','Oct','Dec'],
                30: ['Apr', 'Jun','Sep','Nov'],
                28: ['Feb']}
In [86]:
# Your code here
monthLengths = reverseDictionary(daysOfMonth)
{31: ['Jan', 'Mar', 'May', 'Jul', 'Aug', 'Oct', 'Dec'],
 29: ['Feb'],
 30: ['Apr', 'Jun', 'Sep', 'Nov']}

11. Digging deeper and Other Additional Topics

Use the built-in dict function

The dict function can create a dictionary from a list of tuples, where every tuple has two elements.

In [87]:
dict([('DEU', 49), ('ALB', 355), ('UK', 44)]) # a list of tuples for country codes
{'DEU': 49, 'ALB': 355, 'UK': 44}

A tuple that is not part of a list will not work:

In [88]:
dict(('USA', 1))
ValueError                                Traceback (most recent call last)
<ipython-input-88-c30d6bfc189c> in <module>
----> 1 dict(('USA', 1))

ValueError: dictionary update sequence element #0 has length 3; 2 is required

Calling dict with zero arguments creates an empty dictionary:

In [89]:
dict() # creates an empty dict

The get method

The method get is used to avoid the step of checking for a key before updating.
This is possible because this method will return a "default" value when the key is not in the dictionary.
In all other cases, it will return the value associated with the given key.

In [90]:
{'Jan': 31,
 'Feb': 29,
 'Mar': 31,
 'Apr': 30,
 'May': 31,
 'Jun': 30,
 'Jul': 31,
 'Aug': 31,
 'Sep': 30,
 'Oct': 31,
 'Nov': 30,
 'Dec': 31}
In [91]:
daysOfMonth.get('Oct', 'unknown') 
In [92]:
daysOfMonth.get('OCT', 'unknown') 

Remember that if we try to access a non-existing key directly, we'll get a KeyError:

In [93]:
KeyError                                  Traceback (most recent call last)
<ipython-input-93-13b9f48288b7> in <module>
----> 1 daysOfMonth['OCT']

KeyError: 'OCT'

Using get, allows us to avoid that error:

In [94]:

QUESTION: Why don't we see anything?

The update method

dict1.update(dict2) mutates dict1 by assigning the key/value pairs of dict2 to dict1.

In [95]:
# let's remind ourselves of the contributions
{'uma52': {2015: 10, 2016: 15},
 'setam$3': {2012: 23, 2013: 34, 2014: 17},
 'rid12': {2009: 5, 2010: 18, 2012: 4}}
In [96]:
newContributions = {'brix4': {2011: 39, 2013: 27, 2015: 41},
                    'uma52': {2017: 21}}
In [97]:

QUESTION: What didn't you see an output from running the cell above?

In [98]:
{'uma52': {2017: 21},
 'setam$3': {2012: 23, 2013: 34, 2014: 17},
 'rid12': {2009: 5, 2010: 18, 2012: 4},
 'brix4': {2011: 39, 2013: 27, 2015: 41}}

QUESTION: Why did the 2015 and 2016 contributions for uma52 disappear?

The clear method

We can wipe out the content of a dictionary with clear:

In [99]:
letters = {"a" : 1, "b" : 2}
In [100]:

What does "hashable" mean?

When Python stores the keys of a dictionary in memory, it stores their hashes, which is an integer returned by the hash function. Only immutable objects can be hashed.

In [101]:
In [102]:
hash(['Feb', 2015])
TypeError                                 Traceback (most recent call last)
<ipython-input-102-808a8ea426e9> in <module>
----> 1 hash(['Feb', 2015])

TypeError: unhashable type: 'list'
In [103]:
hash( ('Feb', 2015) ) # Tuples are hashable even though lists are not
In [104]:
hash(123456) # numbers are their own hash value

At this point, you don't have to worry about why the keys are hashed, or how the hash function works!
Take more advanced CS courses to learn more.