Tuples and dictionaries#
Lists are also called collections, because they are a collection of different things.
Python has more types of collections:
tuple
- read-only (immutable) variant of a list. Functions that return multiple results return them as tuples. Rarely used.dict
- dictionary, for non-ordered collections, like phone books. Consists of key-value pairs (in a phone book: names are the keys, the phone numbers the values). Keys act as indices, but in contrast to lists, are unordered and can be of arbitrary type, for instance, strings. Dictionaries are also called “mappings” since they maps keys to values.
Tuples#
Tuples can be created by enclosing tuple items in parentheses (not square brackets as for lists):
a_tuple = (1, 2, 3, 4)
Caution: The parentheses are pure decoration - it’s the comma that makes a tuple. For instance, a trailing comma after a value is sufficient to generate a tuple - this is a frequent cause for bugs. But always use parentheses to clearly indicate in your code that you are defining a tuple!
# a_tuple = 1,2 # this may look like the float 1.2 to some of you
# print(type(a_tuple), a_tuple)
# also_a_tuple = 1, # note the trailing comma after 1
# print(type(also_a_tuple), also_a_tuple)
# clearly_a_tuple = (10, 20) # always use parentheses
# print(type(clearly_a_tuple), clearly_a_tuple)
a_tuple = 1
((1,), tuple)
Tuples are immutable - you cannot change its values, append to it, or delete from it:
a_tuple = (1, 2, 3, 2, 4)
len(a_tuple)
5
Tuples behave more or less like immutable lists: Just as with lists, you can obtain the number of elements in a tuple with the len
function: len(a_tuple)
. Indexing works for tuples works the same as for lists, using square brackets: a_tuple[0]
will return the first element of the tuple.
If you need to change the content of a tuple, cast it to a list:
a_tuple = (1, 2, 3, 2, 4)
list_from_tuple = list(a_tuple) # cast tuple to list
print(type(list_from_tuple))
list_from_tuple[3] = 100 # this works
<class 'list'>
Clicker question “tuples and sets 1” (Click me!)
What is the output of this code?
my_set = (1, 12, 4, 19, 28)
my_set[2] = 40
print(my_set)
Dictionaries#
Dictionaries are quite useful for representing data that is not an ordered sequence of elements but that links two different sets of elements, like names and phone numbers, of animal ids and test scores.
Dictionaries can hold any value, like a list. Unlike lists, they can have arbitrary indices, like strings or floats, not just integers.
They consist of key:value
pairs, where both the key and the value can be almost any python object (numbers, strings, tuples (but not lists)).
Create with {key1: value1, key2: value2, ...}
.
Access the values by using the key as an index my_dict[
key_name]
Assign new keys or overwrite existing keys in an existing dictionary simply by assignment: my_dict['new_or_existing_key'] = new_value
Delete key:value pairs with del(my_dict['key_name'])
# A phone book can be represented as two "parallel" lists - one with the names, and one with the phone numbers
names = ['Tom', 'Alice']
phone_numbers = [125324123, 432246234]
# We can represent the same data using a dictionary, with names as keys, and phone numbers as values
phone_book = {'Tom': 125324123, 'Alice': 432246234}
print(phone_book)
# Access values using the key as in inside inside brackets
phone_book['Tom']
# Change values of existing keys:
phone_book['Tom'] = 99999999
print(phone_book)
# Add new keys to an existing dictionary:
phone_book['Bob'] = 46347347
print(phone_book)
# Delete a key:value pair
del(phone_book['Bob'])
print(phone_book)
{'Tom': 125324123, 'Alice': 432246234}
{'Tom': 99999999, 'Alice': 432246234}
{'Tom': 99999999, 'Alice': 432246234, 'Bob': 46347347}
{'Tom': 99999999, 'Alice': 432246234}
Why are dictionaries useful?#
First, dictionaries allow you to link to related datasets, like names and phone numbers, or animal names and behavioral scores.
Second, it makes code more clear and readable, because dictionaires allow you to access data using keys as more meaningful indices. With a list, you can only use integers as indices. The integer corresponds to the position of the item in the list:
phone_numbers = [125324123, 432246234]
phone_numbers[0] # unclear who this number belongs to
But for a phone number, the important thing is the owner’s name, not where in the list it exists. With dictionaries, you can use the name as an “index” - the key. The meaning of the value in the dictionary is obvious from the code because it is made explicit:
phone_book = {'Tom': 125324123, 'Alice': 432246234}
phone_book['Tom'] # this is clearly Tom's phone number
Looping over key/value pairs in a dictionary:#
Using the items()
method attached to a dictionary in a for loop allows you to iterate over key:value pairs:
for key, value in my_dict.items():
do_stuff
phone_book = {'Tom': 123, 'Alice': 246234, 'Yolanda': 110}
for key, val in phone_book.items():
print(key, val)
Tom 123
Alice 246234
Yolanda 110
Clicker question “composites all” (Click me!)
Which of these statements will fail?
a = [1,12,4,19,28, 54]; a[10] = 4
a = (1,12,4,19,28, 54); a[10] = 4
a = {1,12,4,19,28, 54}; a[10] = 4
a = {1: 12, 4: 19, 28: 54]; a[10] = 4
Bonus: Useful dict functions#
my_dict = {} # create an empty dict called my_dict
my_dict[key] = new_value # adds new and overwrites existing key:value pair
my_dict.update(other_my_dict) # "merge" two dictionaries, adds new and overwrites existing key:value pairs
key in my_dict # check if a key is in the dictionary
my_dict.keys() # "view" of all keys in the dictionary, can cast to list
my_dict.values() # "view" of all values in the dictionary, can cast to list
del my_dict[key] # remove key:value pair, indexed by "key"
phone_book = {'Tom': 123, 'Alice': 246234, 'Yolanda': 110}
print(phone_book.keys(), phone_book.values())
print('Olaf' in phone_book)
# new key/value pairs will be added, values for existing keys will be overwritten
phone_book.update({'Tom': 984703, 'Francoise': 123156, 'Alan': 9630})
print(phone_book)
dict_keys(['Tom', 'Alice', 'Yolanda']) dict_values([123, 246234, 110])
False
{'Tom': 984703, 'Alice': 246234, 'Yolanda': 110, 'Francoise': 123156, 'Alan': 9630}
Side note: Producing nicer prints with string formatting#
f-strings (short for “formatted string literals”)- will substitute variable names with their value when printing:
prepend string with
f
:f"test"
orf'test'
put variable names to print in curly brackets
{}
See the python docs for more details.
When the f-string is printed, the variable name in curly brackets is substituted by its value:
name = 'Tom'
age = 10
print(f"{name}'s age is {age}")
Tom's age is 10
For completeness (so you can read old code): Another way of doing this is with .format
. But please, use f-strings - they are more readable!
name = 'Tom'
age = 10
print("{0}'s age is {1}".format(name, age))
Tom's age is 10