This is an archived version of the course and is no longer updated. Please find the latest version of the course on the main webpage.

Sequence type - Lists

Ok, let us add more advanced data types to our Python programming ‘toolbox’, so that we can solve problems more efficiently.

So far, we only looked at single variables.

What if we want to just refer to a group or collection of variables together as a whole?

I would definitely not want to type out student1, student2, student3, student4, etc. for my whole class of students!

Lists to the rescue!

Fortunately, Python provides us with a built-in data type called list to represent a sequence of objects.

A list is well, a list! A list can be expressed by enclosing the list of objects with square brackets, and separate each item in the list with commas.

>>> students = ["Abraham", "Bella", "Connor", "Da-ming", "Enya"]
>>> 

TIP: Good programming practice - notice that I used the plural students as my variable name!

In Python, you can mix different types of objects in the same list (although in this case you should rethink whether a list is the best representation for your use case).

>>> mixed_buffet = [1, "Two", 3.03, 4j]

You can even have a list inside another list (and inside yet another list). This is called a nested list.

>>> list_in_list = [1, 2, [3, 4, [5, 6, 7], 8], 9, [10, 11]]

You can also use the `list()’ constructor to construct a new list object.

>>> x = list("abc")    # converts the string "abc" into a list ["a", "b", "c"]
>>> print(x)

Accessing elements in a list

Each item in the list is called an element. You can access each element by referring to its index.

The index starts from 0 (i.e. the first item’s index is 0). [Special attention to users of MATLAB and other languages that start at 1!]

>>> students = ["Abraham", "Bella", "Connor", "Da-ming", "Enya"]
>>> print(students[0])       # First element: "Abraham"
>>> print(students[1])       # Second element: "Bella"

Python also allows you to access elements in a list in a reverse order, with negative indices.

>>> print(students[-1])      # First element from the end: "Enya"
>>> print(students[-2])      # Second element from the end: "Da-ming"

Accessing elements in a list with indices

You can also modify the value of an element using indices.

>>> students[2] = "Catherine"
>>> print(students)

If you have another list inside a list…

>>> x = [1, 2, [3, 4, 5], 6]
>>> print(x[2])                # [3, 4, 5]
>>> print(x[2][1])             # 4          

List slicing

Python also provides a convenient way to perform list slicing to slice out a subset of your list.

>>> print(students[1:4])     # ["Bella", "Connor", "Da-ming"]

I find the best way to think about “slicing” is to “slice” up your list between the elements, as in the image below.

Slicing a list

What happens when you do not provide a start or end index? Try this and see what happens!

>>> print(students[:3])
>>> print(students[2:])    
>>> print(students[:])    

Here are some more complicated slicing operations. Try to figure out what each is really doing (Google if you need to!)

>>> print(students[:])    
>>> print(students[0:5:2])
>>> print(students[:-3])
>>> print(students[-2:])
>>> print(students[::-1])      # this last one is an interesting Python 'idiom' or 'recipe'!

Appending new items to a list

You can add new items to the end of the list by using its append() method (list is an object!)

>>> numbers = []          # this create a new empty list
>>> numbers.append(6)
>>> print(numbers)
>>> numbers.append(2)
>>> print(numbers)

Deleting items from a list

You can delete items from a list with the del operator.

>>> numbers = [1, 2, 3]
>>> print(numbers)
>>> del numbers[1]
>>> print(numbers)

Getting the number of elements in the list

You can get the size of the list with the built-in len() function. In fact, you can use this for all of the other data types we will discuss later.

>>> numbers = [1, 2, 3]
>>> print(len(numbers))

List operators

In programming, operators like + and - can be overloaded to perform a different operation depending on what the operands are.

So, you can concatenate two lists by ‘adding’ the list together.

Try this and see what happens.

>>> print([1, 2] + [3, 4, 5])

And you can replicate elements in a list by ‘mutiplying’ it with a scalar.

Try this and see what happens.

>>> print([1, 2] * 3)

The membership operator in is also useful for checking whether a particular object is in a list. This returns a bool (True or False).

>>> print(3 in [1,2,3,4])
>>> print(3 not in [1,2,3,4])
>>> print("snake" in ["I", "am", "not", "afraid", "of", "Python"])

Advanced: Beware of side-effects!

Remember that variables point to the location of an object. It does not make a copy of the object!

>>> x = [1, 2, 3]
>>> y = x
>>> print(x)
>>> print(y)
>>> print(id(x) == id(y))

What happens when you modify an element in a list? Try it!

>>> y[1] = 4
>>> print(x)
>>> print(y)

If you want to preserve the original copy of the list, then you should make a copy of the object with the copy() method of list and assign a new variable to it.

>>> x = [1, 2, 3]
>>> y = x.copy()
>>> print(x)
>>> print(y)
>>> print(id(x))
>>> print(id(y))
>>> y[1] = 4
>>> print(x)          # [1, 2, 3]
>>> print(y)          # [1, 4, 3]

Even more advanced: if you have a reference to an object inside a list, then you may even have to go further and use deepcopy() method.

>>> x = [1, 2]
>>> y = [3, x, 4]
>>> z = y.copy()
>>> print(y)          # [3, [1, 2], 4]
>>> print(z)          # [3, [1, 2], 4]
>>> print(id(z[1]) == id(y[1]) == id(x))
>>> z[1][0] = 5
>>> print(x)          # [5, 2] 
>>> print(y)          # [3, [5, 2], 4]
>>> print(z)          # [3, [5, 2], 4]

If you replace y.copy() with y.deepcopy(), then changing z[1][0] will not modify x[0]. Try it!

BONUS NOTE: In C, C++ and Java, such built in types are known as arrays. However, you have to define its maximum size in advance. Very inconvenient!