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"
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.
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!