Lists

Quiz: counts toward finishing the lesson. Check: just for practice.

Introduction

A list is an ordered collection of objects of any type. You can have lists of floats, strings, objects made from classes you've defined, and more. You can even have lists contain other lists. You're allowed to mix the types of objects in a list, for example you can have a list that contains both integers and strings.

Most lists contain multiple values, but we can have lists of one or zero values, which can be useful. Run this cell to see a few lists.

Type hinting with lists

Type hinting can be used to specify the expected data type of elements in a list. For example:

def get_average(numbers: list[float]) -> float:
    return sum(numbers) / len(numbers)

In the example above, the get_average function takes a single argument, numbers, which is expected to be a list of float values. The list[float] syntax specifies that the numbers argument is a list whose elements are of type float. The function's return value is indicated to be of type float.

Here is how our examples look with type hinting added.

Type hinting with mixed data types

To type hint a list with a mix of items, you can use the | operator, which lets you specify that a value can be one of several types. Here is how we would type hint the some_stuff variable.

In this code, the some_stuff variable is declared as a list of items that can each be an int, a str, a float, or a nested list of str values, using the | operator.

Type hinting with any data type

If your list can contain any type of object, you can use the type annotation object.

some_stuff: list[object] = [98, "Fido", -34.925, ["Phantom", "Tollbooth"]]

It's important to note that using the object type can make it harder to catch type errors, and can also make the code less readable, since the type of the objects in the list is not specified. In general, it's recommended to use more specific types where possible.

len

With lists, len() returns the number of elements in the list:

Indexing and slicing

Indexing and slicing work the same with lists as they do with strings. Try these examples one at a time.

When you index into a nested list to get a sublist, you can then index into that list. Try the following to get the list within some_stuff, then the item "Tollbooth" within that sublist, and then its first character:

in, not in

Also like strings, we can use in and not in. With these two operators, the second operand can be a string or a list, and the first operand can be any value. Try these examples to see for yourself:

What happened with those last two examples? The string "Phantom" is not in some_stuff. It's in a list that's in some_stuff. That list is at index 3, so we were able to find it there.

Let's look at some more things we can do, with new list examples.

min and max, sort

There are min and max functions we can use. Try these:

The min and max functions wouldn't make sense for a list like some_stuff, since Python doesn't know how to compare the different types in that list. There's also a sort method we can use.

You'll notice that nothing prints out when you try those. But now look at the lists again:

The sort method works "in place": it changes the original list. Sorting also wouldn't make sense for some_stuff, again because Python doesn't know how to compare the different types in that list. Try it and see!

Check your understanding. Predict the result. Look at what sort gives back.

nums = [3, 1, 2]
result = nums.sort()

Predict what each variable holds after the program finishes. The program is not run for you. Change the values below to your predictions:

  • final_nums is the value of nums at the end
  • final_result is the value of result at the end
Hint 1

sort rearranges the list itself and gives back None, so result is None.

Concatenation

We can concatenate lists with the + operator.

Here's one more list example for us to practice on.

Check your understanding. Predict the result. One of these changes a list and one makes a new one.

a = [1, 2]
b = a + [3]
a[0] = 9

Predict what each variable holds after the program finishes. The program is not run for you. Change the values below to your predictions:

  • final_a is the value of a at the end
  • final_b is the value of b at the end
Hint 1

a + [3] makes a new list, so b is not affected when a[0] = 9 changes the first item of a.

Iterating through a List

Lists are iterable, so we can use a for loop to access each element. For example, try this loop:

The following loop prints out a running total of the values in the list:

Lists of objects

Let's reintroduce the BankAccount class we defined in an earlier section:

We can make a list of BankAccount objects like this:

What if we want to access the balance of the first account in the list? We can do that like this:

Here account_list[0] gives us a BankAccount object, and .get_balance() returns the balance of that object.

List Comprehensions

List comprehensions are a concise way to construct a new list by applying some transformation to an existing list. Anything you can loop over, such as a list or a range, is called an iterable. For example, the following code creates a new list whose elements are double the elements in fun_floats (defined earlier):

Here's a similar example that works from a range instead of a list:

We can optionally filter out certain values from the original list (or other iterable).

In this example, the original iterable was a range. If a value in that range is odd (the remainder of dividing by 2 is 1), then we apply the transformation (multiplying by 2). Note that values are filtered out before the transformation is applied. If we had doubled the numbers and then filtered out the even ones, then the new list would have been empty.

We can also use a list comprehension to filter without applying a transformation:

Don't let this new use of the for and if keywords confuse you. List comprehensions are a related concept to for loops and if statements, but a different flavor. The best way to get comfortable with list comprehensions is to try the exercises.

Quizzes

  1. Write a function named every_other that takes a list as a parameter and returns a list that contains only every other element starting with the first one. For example, if the original list is [7, "joe", "apple", 9.81, False], then the new list should be [7, "apple", False]. Use slicing.
  1. Write a function named array_sum that takes a list of strings as a parameter and returns the total number of characters in all the strings.
  1. Write a function named rev_string_list that takes a list of strings as a parameter and returns a list that contains the reverse of each of those strings. Use a list comprehension.
  1. Write a function named contain_string that takes a list of strings and a target string as parameters, and returns a list of the strings from the original list that contain the target string. Use a list comprehension. As an example, if the function call is contain_string(["cats", "tacks", "scat", "stack"], "cat"), then the return value should be ["cats", "scat"], because "cats" and "scat" both contain "cat".

Projects

Practice what you learned in your own editor. Each project has its own page.