Week 5: Lists; More Functions

Week 5 Goals

  • Learn to represent data using lists

  • Learn about list indexing other operations

  • Learn how lists are used by functions

  • Learn how characters are represented using ASCII encoding

Unresolved directive in week05.adoc - include::inclass.adoc[]

Week 5 Code

  • rectangle.py and circle.py: more practice with functions

  • lists.py: practice with lists and list operations

  • list_functions.py: practice with functions that use lists

Week 5 Concepts

Lists

Until now, we have seen that a variable can hold a single value, e.g. if we set the variable x equal to 5, then x only holds the value 5.

A list is a variable that can hold multiple values, which are stored in an ordered manner.

In the following code, we use the bracket notation to create a list called nums that holds the values 5, 6, 4, and 2, in that order:

nums = [5, 6, 4, 2]
print(nums) # prints [5, 6, 4, 2]

We can access individual elements of a list using a 0-based index:

nums = [5, 6, 4, 2]

print(nums[1]) # prints 6

nums[0] = 11
print(nums) # prints [11, 6, 4, 2]

We can also get the number of elements in a list using the len function:

nums = [11, 6, 4, 2]
print(len(nums)) # prints 4

Working with Lists

We can iterate over the elements of a list in the same manner that we did with strings: either by iterating one element/character at a time, or by using the indices within the valid range to get each element/character by its index.

The following two for-loops produce the exact same output:

dogs = ['snoopy', 'bluey', 'pluto']

for dog in dogs:
    print(dog + " is a good dog")

for i in range(len(dogs)):
    print(dogs[i] + " is a good dog")

We can add elements to the end of a list using the append method:

dogs = ['snoopy', 'bluey', 'pluto']

dogs.append('underdog')

print(dogs) # prints ['snoopy', 'bluey', 'pluto', 'underdog']

When are also able to concatenate two lists in order to create a larger list. Note that this does not change either of the two lists, but rather creates a new one:

weekdays = ['mon', 'tue', 'wed', 'thu', 'fri']
weekend = ['sat', 'sun']

week = weekdays + weekend

print(week) # prints ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

Often we may want to start with an empty list, i.e. one containing no elements, and then add some number of elements to it. The following code asks the user how many elements to add, then appends elements as they are provided:

songs = []
n = int(input("How many favorite songs do you have? "))
for i in range(n):
    song = input("Tell me one of your favorite songs: ")
    songs.append(song)
print(songs) # prints all songs in the list

Passing Lists to Functions

Lists can be passed as arguments to function. The parameter of the function will refer to the entire list.

The following function calculates the sum of the values in the list that is passed as an argument:

def sum(lst):
    total = 0
    for i in range(len(lst)):
        total = total + lst[i]
    return total

An important difference between lists and other variables is that when a list is passed to a function, the function can modify the list, whereas it cannot modify arguments such as ints, floats, and strings.

For instance, consider the following function, which is attempting to change the value that is sent to it:

def change(x):
    x = 0

Now let’s say we call this function as follows:

a = 5
change(a)
print(a) # prints 5

The code still prints 5, because the change function has only changed the value of the parameter x, not the value of the argument a.

However, lists behave differently when passed to functions:

def change_list(lst):
    lst[0] = 0
    lst.append(17)

Now when we call this function, the list is changed:

nums = [5, 7, 9]
change_list(nums)
print(nums) # prints [0, 7, 9, 17]

This happens because the parameter lst and the argument nums are aliases for the same list. This means that the list has two names: lst and nums.

Let’s take a look at the stack diagram to see why this happens!

First, here is what the stack diagram looks like for the code that calls change_list: the nums variable refers to the list containing [5, 7, 9]:

Stack diagram for function with list as local variable

When change_list is called, we pass nums as the argument. This means that the value in the box labeled nums is copied to the box labeled lst, i.e. the parameter of the change_list function. What’s in the box labeled nums is the arrow pointing to the list, so now lst has an arrow pointing to that list, too.

Stack diagram for function with two variables referring to same list

Now when change_list runs the first line of code — lst[0] = 0 — we change what is in the box for element #0 of the list. So the arrow now points to 0 instead of 5.

Stack diagram for function that has changed value in list

Next, when change_list runs the second line of code — lst.append(17) — a new box is added to the list, and it points to 17.

Stack diagram for function that has appended value to list

Finally, when change_list returns and we go back to main, the variable nums is still pointing to the same list, which has been updated by change_list. This is why nums[0] is now 0 instead of 5.

Stack diagram for function that has had list modified after calling another function