Closure#
Syllabus Week 8: Dictionaries and Tuples#
Dictionary, a collection of key-value pairs
Creating dictionaries: enclosing key-value pairs in curly brackets
Keyword
in
for dictionaries operates on keys, not valuesTraversing a dictionary
Adding key-value pairs to the dictionary
Dictionaries are mutable
Tuple, an immutable sequence of values
Creating tuple with or without parenthesis
Unpacking, i.e
a, b = my_function()
Using tuple as a return value
Advanced#
Advanced 8.1: Nested Dictionaries#
We have mentioned that values in dictionaries may be of any type, including other dictionaries. Check for example a following nested dictionary.
person_data = {
"Jakob": {
"age": 25,
"height": 175,
},
"Josefine": {
"age": 30,
"height": 165,
},
"Morten": {
"age": 37,
"height": 189,
},
}
print(person_data["Jakob"]["age"])
Copy and run the code below which illustrates how to create and traverse a nested dictionary. Can you explain what key
, nested_key
and value
refers to?
nested_weather_data = {"Monday": {"temperature": 21, "wind_speed": 4.2},
"Tuesday": {"temperature": 18, "wind_speed": 3.2},
"Wednesday": {"temperature": 15, "wind_speed": 1.8},
"Thursday": {"temperature": 17, "wind_speed": 2.6},
"Friday": {"temperature": 25, "wind_speed": 3.9}}
print(nested_weather_data)
print(nested_weather_data["Monday"])
print(nested_weather_data["Monday"]["temperature"])
for key in nested_weather_data:
print(key, end=" ")
nested_dictionary = nested_weather_data[key]
for nested_key in nested_dictionary:
value = nested_dictionary[nested_key]
print(nested_key, value, end=" ")
print("")
Advanced 8.2: Efficiency of Dictionaries#
Dictionaries have a very efficient way of storing and retrieving elements. In the code below, we make a list with a million elements and a dictionary with a million elements. We then measure how long it takes to find a certain element in each data structure.
For this we use a time
module that has a function time()
that returns the current time in seconds.
import time
my_dict = {}
my_list = []
for i in range(1000000):
my_dict[str(i)] = i
my_list.append(str(i))
t = time.time()
search_list = "1000000" in my_list
time_list = time.time() - t
print("Time taken using list:", time_list * 1000, "ms")
t = time.time()
search_dict = "1000000" in my_dict
time_dict = time.time() - t
print("Time taken using dictionary:", time_dict * 1000, "ms")
print("Dictionary is", time_list / time_dict, "times faster than list")
When searching a list, Python has to check each element. On the other hand, dictionary lookups uses a hash function to find the element, which is much faster. The explanation of this is a bit technical but the main point is that dictionaries are much faster than lists for looking up elements, especially when the number of elements is large.
Advanced 8.3: Dictionary Methods#
Run the following code.
book = {"Title": "The Hitchhiker's Guide to the Galaxy", "Author": "Douglas Adams", "Genre": "Science fiction"}
print(book.keys())
print(book.values())
print(book.items())
The keys()
, values()
, and items()
are built-in methods operating on dictionaries and giving access to the keys, values, and key-value pairs. These methods return a dictionary view object, which is a data type that behaves differently than date types you’ve seen so far. You can iterate over the view objects, but you cannot access individual elements by index. If you need to access individual elements, you can convert the view object to a list.
Check the code below to see how you can iterate over the keys, values, and key-value pairs of a dictionary.
grades = {"Josefine": 12, "Jakob": 10, "Alice": 7, "Morten": 10}
for key in grades.keys():
print(key)
for value in grades.values():
print(value)
for key, value in grades.items():
print(key, value)
In the last example, since items()
returns each key-value pair as a tuple, you can use variable unpacking. This enables you to have two iteration variables, one which loops over the keys and one which loops over the values.
Advanced 8.4: Constructor dict
#
Run the following code.
numbers = dict(x=1, y=2, z=3)
print(numbers)
fruits = dict([("first", "apple"), ("second", "orange"), ("third", "banana")])
print(fruits)
sequences = dict(first_seq=dict(a = [1, 2, 3]), second_seq=dict(b = [4, 5, 6]), third_seq=dict(c = [7, 8, 9]))
print(sequences)
The constructor dict
can be used to create a dictionary. The key-value pairs may be given as keyword arguments, or as a list of tuples. This is just another way to create a dictionary, which you might see in other people’s code.
Advanced 8.5: Unpacking Using Single Double Asterisk#
You can unpacks a sequence into individual positional arguments when passed to a function. See the example below.
def example_func(a, b, c):
print(a, b, c)
my_input = (1, 2, 3)
example_func(*my_input)
If you unpack a dictionary, this passes key-value pairs as keyword arguments to a function.
def example_func(a, b, c):
print(a, b, c)
my_dict = {'b': 2, 'c': 3, 'a': 1}
example_func(**my_dict)
Advanced 8.6: Variable Length Arguments#
You can define functions that take a variable number of arguments. For example, check the code below.
def example_variable_length_args(a, b, c, *args):
print(a, b, c)
print(args)
print(type(args))
example_variable_length_args(1, 2, 3, "First", "Second", "Third")
Advanced 8.1: Python Haiku#
With inspiration in The Old Pond by Matsuo Bashō, we created a Python program that generates Haiku-like text. Try our Haiku generator several times, to see some of the outputs it can produce.
import random
thing = random.choice(["pond", "shore", "stream", "pine", "grove", "oak", "trail"])
noise = random.choice(["water", "splashing", "leaves", "rustling", "footsteps"])
animal = random.choice(["frog", "sparrow", "cat", "mouse", "deer", "squirrel"])
action = random.choice(["jumps in", "leaps over", "steps out", "flies by"])
print("The old", thing)
print("a", animal, action)
print("sound of", noise + ".")
The outcome may sound silly if the words are not related. For example, if the thing is a pine tree, the noise should be related to the tree (leaves, rustling), and if the thing is a pond, the noise should be related to water (water, splashing). Make a dictionary called thing_noise
, with keys being things and values being a list of noises for that thing. The same noise may be in different lists. For example, the noise water
may be related to both pond
and shore
. Now, you can draw a thing by accessing the dictionary keys and a noise by accessing the corresponding value, like this:
thing = random.choice(list(thing_noise.keys()))
noise = random.choice(thing_noise[thing])
Ensure the relation between animal and action with another dictionary called animal_action
.