Preparation#

A note about the reading material and preparation exercises. The reading material and preparation exercises both cover the same programming concepts but with slightly different approaches. The reading material aims to explain the concepts, while we designed the preparation exercises for you to try things out. You can decide which to start with. Some prefer reading the chapters from the book first to feel more prepared for the exercises, while others may dive into the exercises and use the book to clarify things as needed. If you’re finding programming challenging, you might benefit from reading the chapters first, then doing the exercises, and returning to the book for clarification.

Reading material#

In the Think Python (TP) book, lists are covered in Chapter 9 Lists.

Copy-and-Run#

Prep 6.1: Creating Lists#

Run each of the following code snippets.

odd_digits = [1, 3, 5, 7, 9]
print(odd_digits)
even_digits = [0, 2, 4, 6, 8]
print(even_digits)
common_allergies = ['peanuts', 'shellfish', 'dairy', 'eggs', 'gluten']
print(common_allergies)
noble_gasses = ['helium', 'neon', 'argon', 'krypton', 'xenon', 'radon']
print(noble_gasses)

By placing items separated by commas inside square brackets, you created a list. Lists allow you to store multiple items under the same variable name.

Look at the following attempts at creating lists. Do you think they will run? Try it out!

mixed_list = [1, 'hello', 3.14, True]
print(mixed_list)
numpad_buttons = [[7, 8, 9], [4, 5, 6], [1, 2, 3], [0]]
print(numpad_buttons)
i_am_empty_inside = []
print(i_am_empty_inside)

Prep 6.2: List Indexing#

Now, try running the following code.

list_of_numbers = [10, 20, 30, 40, 50]
print("item at index 0:", list_of_numbers[0])
print("item at index 3:", list_of_numbers[3])

You access list elements by using square brackets [] after the list variable name. The number inside the square brackets is the index of the element you want to access. Python is a zero-indexed language, so the first element of a list has an index of 0, the second element has an index of 1, and so on.

Now, try this code.

noble_gasses = ['helium', 'neon', 'argon', 'krypton', 'xenon', 'radon']
print("item at index 1:", noble_gasses[1])
print("item at index -1:", noble_gasses[-1])
print("item at index -2:", noble_gasses[-2])
print("item at index -3:", noble_gasses[-3])

A negative index can be used to access elements from the end of the list!

The figure below shows how the elements of a list are indexed.

image

Prep 6.3: List Slicing#

Run now the following code.

my_list = ["Zero", "One", "Two", "Three", "Four", 
           "Five", "Six", "Seven", "Eight", "Nine"]
print(my_list[2:5])
print(my_list[3:8:2])
print(my_list[0:10:3])

Slicing accesses a range of elements in a list. The syntax for slicing is list[start:stop:step], which is similar to range. And like with range, you can omit the default values. It is a good idea to experiment with slicing to understand how it works. Run the following code and experiment with different values.

my_list = ["Zero", "One", "Two", "Three", "Four", 
           "Five", "Six", "Seven", "Eight", "Nine"]
print(my_list[::2])
print(my_list[:-1])
print(my_list[::-1])
print(my_list[3:])
print(my_list[:2])

Now, see yet another use of slicing.

my_list = ["Zero", "One", "Two", "Three", "Four", 
           "Five", "Six", "Seven", "Eight", "Nine"]
second_list = my_list[3:8]
print(second_list)

It is important to remember that indexing returns a single element, while slicing returns a list.

Prep 6.4: Lists Are Mutable#

You have seen how indexing and slicing can be used to access the element or elements in a list.

Now, try running the following code.

my_list = ['uno', 'dos', 'tres', 'cuatro', 'cinco']
my_list[0] = 'one'
print(my_list)
my_list[-1] = 'fem'
print(my_list)
my_list = ["Zero", "One", "Two", "Three", "Four", 
           "Five", "Six", "Seven", "Eight", "Nine"]
my_list[3:8] = ['3', '4', '5', '6', '7']
print(my_list)

You can use indexing and slicing to change the value of an element or a range of elements in a list. This means that you can modify the list after it has been created. We say that lists are mutable.

Try these examples of modifying lists.

this_list = ["apple", "banana", "cherry"]
this_list[3:] = ["blackcurrant", "watermelon"]
print(this_list)
this_list[1:3] = []
print(this_list)

While the examples you just tried might look like reassignments, they are not: you were modifying the list, not creating a new one. This was not possible with integers, floats, or strings because they are immutable.

When you reach the examples on referencing lists, you will see other consequences of lists being mutable.

Prep 6.5: Functions for Lists#

Try running the following code.

digits = [3, 117, 4, -1.9, 5, 9.8, 0]
print("Length of digits:", len(digits))
print("Sum of digits:", sum(digits))
print("Minimum of digits:", min(digits))
print("Maximum of digits:", max(digits))


print("Any:", any(digits))
print("All:", all(digits))

If you are unsure what the functions len, min, max, and sum do, make changes in the code and run it again.

Now, try to run this code.

test_1 = 'Anna' == 'Anna'
test_2 = 'Anna' == 'anna'
test_3 = 'Anna' == 'ANNA'
test_4 = 'Anna' == 'Anne'

all_tests = [test_1, test_2, test_3, test_4]
print('All tests:', all(all_tests))
print('Any tests:', any(all_tests))

Print some of the elements from all_tests. What type are they?

Prep 6.6: List Operators#

Try running this code.

list1 = ['water', 'earth']
list2 = ['fire', 'air']
elements = list1 + list2
print(elements)
elements = elements + list2
print(elements)
elements = elements + 4 * list1
print(elements)

Make sure you understand how the operators + and * work with lists. Also, note in these examples, lines starting with elements = are reassignments.

Now, try to predict what the following code will print. Run the code to check your answer.

spam_list = ["SPAM"] * 5
print(spam_list)
the_best_number = [216] * 7
print(the_best_number)
concat_list = spam_list + the_best_number
print(concat_list)

Prep 6.7: List Methods#

Carefully examine this code and run it.

my_list = [3, 1, 4, 1, 5, 9, 2]
print(my_list)
my_list.sort()
print(my_list)

In the example above, sort() is a method that operates on the list my_list. This is the first time you are encountering a method in Python, so we need to explain some new syntax and learn some new terminology.

Later in the course, when we reach classes and object-oriented programming, you will learn how to define methods. For now, you should know that a method is very similar to a function. However, a method is written to be used with a specific object. In this case, the object is a list, and for now, you can think of an object as a special (slightly more complex) type of variable.

We execute functions by calling them, and the similar term for methods is to invoke them. A method is invoked (executed, run, used) by writing a variable name, followed by a period ., followed by the method name, and finally parentheses with or without arguments.

Look at the code above and identify the lines where the methods are invoked.

A method always operates ton exactly one object, in our case, a lis. What is the name of the list that the method sort() operates on in the code above?

Look at the code above and confirm that:

  • The list was modified by the method. To confirm this, look at the printed output.

  • It is still the same list. To confirm this, notice that we had no reassignments in the code.

Try running this code:

my_list = [3, 1, 4, 1, 5, 9, 2]
print(my_list)
my_list = my_list.sort()
print(my_list)

What can you conclude from the printed result? What does the sort() method return?

Methods may take arguments and may return a value. Below are code snippets where we use some list methods. For each code snippet, identify the method and look at the printed output to see what the method does. Try checking whether the method takes any arguments, and whether it returns a value.

my_list = ["A", "B"]
my_list.append("C")
print(my_list)
models = ['linear', 'quadratic', 'power', 'exponential']
models.pop(1)
print(models)
models.pop(1)
print(models)
my_list = ["A", "B"]
my_list.extend(["C", "D"])
print(my_list)
names = ["Clara", "Alice", "Bob", "David", "Anna", "Eve", "Elvis", "Aaron"]
names.sort()
print(names)
my_list = ["A", "B", "A", "C", "a"]
print(my_list.count("A"))
my_list = ["A", "B", "C", "A"]
print(my_list.index("A"))
print(my_list.index("C"))

Try answering the following questions. If needed, modify the code and run it to check your answers.

  • What is the argument of the pop() method? Does it run without an argument? Does pop() return a value?

  • What happens if you use append() instead of extend() in the code above?

  • Can append() take more than one argument? Can extend() take more than one argument?

  • What if the argument of count() is not in the list? What does count() return in that case?

  • What if the argument of index() is not in the list? What does index() return in that case?

Prep 6.8: Referencing Lists#

Carefully read the following code, and make a prediction of what will be printed. Run the code and examine the output.

a = ['one', 'two', 'three']
b = a
print(a)
b[1] = '2'
print(a)

What you have seen should surprise you.

Here is the explanation of this surprising behavior. After you make an assignment b = a, both a and b point to the same list. And since lists are mutable, you can make changes to this list that are visible in both a and b.

Now look at this code and try to predict what it will print. Run the code to check your answer.

a = ['one', 'two', 'three']
b = a
a.append('four')
print(b)

Try now to predict what the following code will print. Run the code to check your answer.

a = ['one', 'two', 'three']
b = a
a = a + ['four']
print(b)

What you have seen might be confusing. When do a and b point to the same list?

The difference in the last two blocks of code is that append() modifies the existing list, while reassigning creates a new list. So, in the last block of code, the line starting with a = created a new list. It might be difficult to remember how exactly Python handles different cases, and the best strategy is to always check by printing the elements of the list if you are unsure.

Try this code now.

a = ['one', 'two', 'three']
b = a.copy()
a.append('four')
print(b)

The copy() method creates a separate list with the same elements as the original list.

Prep 6.9: Iterating Over Lists#

Try running the following code.

weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
for i in range(len(weekdays)):
    print('Hello ' + weekdays[i])

What you’ve just done is called iterating over a list or traversing a list.

Traversing a list is so common that Python has a special syntax for it. Check it in the next code block. Check it in the next code block.

weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
for weekday in weekdays:
    print('Hello ' + weekday)

Let’s say that you want to print a different message for some of the elements in the list. And say also that you want to create a new list that contains the lengths of the strings in the original list. Run this code to see how it can be done.

weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
lengths = []
for weekday in weekdays:
    lengths.append(len(weekday))
    if weekday == "Monday":
        print("I hate Mondays...")
    else:
        print("I like", weekday + "s")
print(lengths)

Iterating directly over elements of the list is practical. However, if you wanted to change their values, you need to iterate over indices.

Try this code where you loop and change the elements of the list.

distances = [12.8, 10.7, 6.6, 9.9, -0.2, 5.5, -0.3, 14.7]
for i in range(len(distances)):
    if distances[i] < 0:
        distances[i] = 0.0
print(distances)

Run a few more examples of iterating over lists.

recorded_data = [3.0, 4.2, -1, -1, 2.5, 3.7, -1000]
positive_data = []
for value in recorded_data:
    if value > 0:
        positive_data.append(value)
print(positive_data)
weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
temperatures = [20, 21, 17, 22, 24]
for i in range(len(weekdays)):
    print(weekdays[i] + ":", temperatures[i], "degrees")

Prep 6.10: List Constructors#

Try running this code.

vowel_string = "aeiou"
vowels = list(vowel_string)
print(vowels)

Now, try this.

numbers_range = range(20)
numbers = list(numbers_range)
print(numbers)

As you can see, lists can be created from other objects.

Prep 6.11: Functions Modifying Lists#

So far, you have written functions that print something or return a value. Try now running this code, where the function does not have a return statement.

def modify_list(my_list):
    my_list.append("banana")

fruits = ["apple", "orange"]
modify_list(fruits)
print(fruits)

As you can see, you can modify the list by passing it to a function and making changes to it inside the function. You could have returned the modified list, but modifying the list directly is simpler.

Try to change the function modify_list such that it performs the following modifications, without returning the list:

  • Removes the first element of the list.

  • Sorts the list.

  • Extends the list with ["grape", "pear", "kiwi"].

Prep 6.12: The in Operator#

Run this code.

some_list = [1, 2, 3]
print(5 in some_list)
print(1 in some_list)

condition = 13 in [1, 2, 3, 4, 5]
print(condition)

vowels = ['a', 'e', 'i', 'o', 'u']
print('y' in vowels)

As you can see, the in operator checks if an element is in the list. The result is a boolean value.

Now, execute these examples of using the in and not in operators. Remember the syntax of conditional statements: the keyword if , followed by a condition, followed by a colon, and then an indented block of code. Identify the conditions in the code below.

for energy_source in ['wind', 'coal']:
    if energy_source in ['solar', 'wind', 'hydropower', 'geothermal', 'biomass']:
        print(energy_source, "is a renewable energy source.")
    else:
        print(energy_source, "is not a renewable energy source.")
cat_family = ['lion', 'tiger', 'leopard', 'cheetah']
animal = 'bear'
if animal not in cat_family:
    print(animal + " is not in the cat family.")

Prep 6.13: Fix List Problems#

The code below has a few common problems that can occur when working with lists. However, they do not actually cause an error. Can you spot the problems and fix them?

common_allergies = ['peanuts', 'shellfish', 'dairy', 'eggs', 'gluten']
common_allergies = common_allergies.append('soy')
print(common_allergies)
danish_vowels = ['a', 'e', 'i', 'o', 'u', 'y']
english_vowels = danish_vowels[:-1]
danish_only_vowels = danish_vowels[5:5]
print(english_vowels)
print(danish_only_vowels)
afternoon_activities = ['study', 'work', 'exercise', 'relax']
afternoon_activities.extend('sleep')
print(afternoon_activities)

Prep 6.14: Fix List Errors#

Below are snippets of code that cause an error. Try to figure out what the error is and fix it.

list = ['x_ray', 'mri', 'ct_scan']
numbers = list(range(1, 6))
my_favorite_functions = ['max', 'min', 'sum', 'len']
print("The length of a list can be estimated with", my_favorite_functions[4])
spooky_electronics = ['resistor', 'capacitor', 'inductor', 'transistor', 'diode']
spooky_electronics.pop('resistor')
pi_digits = [3, 1, 4, 1]
# removes all even numbers from the list
for i in range(len(pi_digits)):
    if pi_digits[i] % 2 == 0:
        print("Popping", pi_digits[i], "at index", i)
        pi_digits.pop(i)

print(pi_digits)
print(max([1, "2", 3]))
parts = ['A1', 'A2', 'A3', 'B1', 'C1', 'C2']

partsA = parts[:3] 
partsB = parts[3]
partsC = parts[4:]

parts_again = partsA + partsB + partsC

Prep 6.15: Predict the Output#

For each of the following code snippets, try to predict what will be printed before running the code. Then run the code and observe the output.

shrek_movies = ['Shrek', 'Shrek 2', 'Shrek the Third']
print(shrek_movies.append('Shrek Forever After'))
print(shrek_movies)
print(len(['water, earth, fire, air']))
print(len(['water', 'earth', 'fire', 'air']))
print(len([['water', 'earth', 'fire', 'air']]))
my_list = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
print(my_list[1:4])
print(my_list[4:1])
print(my_list[4:1:-1])
greetings = ["Hello", "Hi", "Hey", "Hola", "Bonjour"]
print(greetings.pop())

Self quiz#

Question 6.1#

What is the length of the list my_list after the following code is executed?

my_list = ["12345"]

Question 6.2#

What gets printed when the following code is executed?

my_list = ['apple', 'banana', 'cherry']
print(my_list[1:2])

Question 6.3#

What happens when executing this code?

my_list = ['apple', 'banana', 'cherry']
print(my_list[-1])

Question 6.4#

What happens when executing this code?

data = ["Mike", "Bike", "Michael"]
print(data[len(data)])

Question 6.5#

Which of the code snippets is equivalent to the following code?

my_list = [1, 2, 3, 4, 5]

Question 6.6#

What is the output of the following code?

courses = ["Coding", "Math", "Physics", "Chemistry"]
print(courses[1:-1])

Question 6.7#

What are the types of the variables x and y after this code is executed?

perfect_squares = [1, 4, 9, 16, 25]
x = perfect_squares[2]
y = perfect_squares[2:3]

Question 6.8#

Based on the following list definition, which of the following expressions evaluate to True?

data = [1, 0, -1, 0, 1, 0, -1]

Question 6.9#

Which code correctly adds the element "guanine" to the list dna_bases?

dna_bases = ["adenine", "thymine", "cytosine"]

Question 6.10#

You have defined

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", 
            "Saturn", "Uranus", "Neptune", "Pluto"]

but now you want to remove "Pluto" from the list. Which of the following lines will achieve this?

Question 6.11#

What is the index of the element "Earth" in the list rocky_planets?

rocky_planets = ["Mercury", "Venus", "Earth", "Mars"]

Question 6.12#

What is the value of chess_pieces after the following code is executed?

chess_pieces = ["King", "Queen", "Bishop", "Knight", "Rook", "Pawn"]
chess_pieces[3] = "Meow"

Question 6.13#

What is the length of the list my_list after the following code is executed?

my_list = list(range(1,4)) * 3

Question 6.14#

Which of the lists list1 and list2 contains the element 1 after the following code is executed?

def add_element(lst):
    lst.append(1)
list1 = []
list2 = list1
add_element(list2)

Question 6.15#

What is the index of the element 'Corgi' after the following code is executed?

dogs = ["Beagle", "Corgi", "Akita"]
dogs.sort()

Question 6.16#

What is the value of count after the following code is executed?

materials = ['concrete', 'steel', 'wood', 'glass', 'aluminum']
count = 0
for material in materials:
    if len(material) > 5:
        count = count + 1

Question 6.17#

What is the value of check after this code executes?

check = 'Milan' in ['Rome', 'Milan', 'Venice']

Question 6.18#

In how many of the following lists is the element "hazelnut" found?

nuts1 = ["almond", "walnut", "hazelnut"]
nuts2 = ["Hazelnut", "Pecan", "Pistachio", "Macadamia"]
nuts3 = ["cashew, hazelnut, brazil"]

Question 6.19#

What is stored in the variable important_birthdays after the following code is executed?

important_birthdays = list(range(17, 19)) + list(range(10, 50, 10)) + [100]

Question 6.20#

What is the value of the variable a after the following code is executed?

a = ['D', 'C', 'B']
b = a
b[0] = 'A'

Question 6.21#

What is the value of moons after this code executes?

moons = ["The Moon", "Phobos", "Deimos", "Europa", "Titan"]
moons = moons[1:]
moons = moons[1:]