3.4.1. Lists

Lists are sequences of things. What kinds of things? Well, anything that can be a thing in Python. That is one key fact about lists. A list can be a higgledypiggledy assortment. One list can contain a number, a string, and another list. You should certainly use lists when you want to remember the order in which you saw a sequence of things. But there are other reasons to use lists. They are in some ways the default container type.

Python uses square brackets to enclose lists and commas to separate the elements, so X, Y, and Z are all valid lists:

>>> X = [24, 3.14, 'w', [1,'a']] #  List with 4 items
>>> Y = [100]    # list with one item
>>> Z = [] #empty list

Note in particular that one of the elements of X is itself a list. More on lists containing lists below. The name list is special in Python, because it refers to the type list:

>>> list
<type 'list'>

3.4.1.1. Creating lists

You can use the type name as function of to create lists. So consider the following:

>>> L = list('hi!')

Python interprets this as a request to make a list that contains the same things as the string hi!; that string contains 3 characters, so Python makes L be a list containing three characters:

>>> L
['h', 'i', '!']

Use of the the type as a function that creates instances of the type is a standard practice in Python, so the list function can be fed any sequence as an argument, and it returns a list containing the same elements. A special case is calling list with no arguments at all:

>>> M = list()

This returns a special list called the empty list, which is of length 0, and contains no elements at all:

>>> M
[]

This may seem useless, but it is a great convenience when programming the result be something that is well defined and legal when all the elements have been removed from a list.

3.4.1.2. Indexing lists, list slices

A list is an index where the indices are numbers; items are referred to by their integer indices:

>>> X[0]   # 1st element
24
>>> X[1]   # 2nd element
3.14
>>> X[-1]   # last element
[1,'a']

Thus, indexing starts with 0. This means the highest index that retrieves anything is 1 less than the length of the list. List X has length 4, so the following raises an IndexError:

>>> X[4]   # Raises exception!
...
IndexError: list index out of range

Python also provides easy access to subsequences of a list. The following examples illustrate how to make such references:

>>> X[0:2] # list of 1st and 2nd elements
[24, 3.14]
>>> X[:-1] # list excluding last element

References to subsequences of a list are called slices.

List can be concatenated to make longer lists:

>>> X + Y # Concatenation!
[24, 3.14, 'w', [1,'a'], 100]

Lists allow value assignments, which change the value of a reference in place (in place assignment):

>>> X[2] = 5
>>> X
[24, 3.14, 5, [1,'a']]
>>> X[0:2]
[24, 3.14]

Slices can also be assigned to:

>>> X[0:2] = [1,3]
>>> X
[1, 3, 5, [1,'a']]

Only list-values can be assigned to slices:

>>> X[0:2] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable

The Error message here “TypeError: can only assign an iterable” refers to a general class containing containers called iterables, the root of the the tree in the Section on More Python types. We’ll talk more about iterables later. The important point for now is that iterables include all containers (including lists), but not integers, so:

>>> X[0:2] = [1]

works, but

>>> X[0:2] = 1

does not. A list slice must be filled in by a list; any iterable can be easily turned into a list, but 1 cannot.

Learning how to read and interpret Python errors is an important part of being able to write simple programs in Python. Properly understood, Python’s error-reporting will make it easier for you to fix errors.

As we noted in introducing Python containers, you can check whether something is among the elements of a container by using the operator in.

Note

in is called an operator because it can occur in between its arguments.

Using in on X we find:

>>> 24 in X
True
>>> 6 in X
False

A second property common to all containers is length. To find the length of any container we use the function len:

>>> X = [24, 3.14, 'w', [1,'a']] #  List with 4 items
>>> len(X)
4

Note X has 4 elements, not 5. The last element is a list of length 2:

>>> len(X[-1])
2

3.4.1.3. Lists containing lists

We introduced the list structure by saying a list could contain anything. That includes a list. Lists of lists are useful for many purposes. One of the most intuitive is to represent a table. Suppose we want to represent the following table from some dataset in Python.

\begin{array}[t]{ccc}
 42 & 3.14 & 7 \\
 2 & 4 & 0 \\
 14 & 0 & 0
 \end{array}

We can do that as follows:

>>> Table = [[42, 3.14,7],[2,4,0],[14,0,0]]
>>> Table[0]
[42, 3.14,7]

This means to retrieve the value 42, we can do:

>>> FirstRow = Table[0]
>>> FirstRow[0]
42

But Python allows any expression which has a list as its value to be followed by [index]. That includes the expression Table[0]. It is much more convenient and Pythonic to do this in one step:

>>> Table[0][0]
42

So in general, thinking of a table as a list of rows, each of which is a list, we can access the element in row i, column j, with Table[i][j].

3.4.1.4. Changing the beginning and end of a list

An important routine task in computing is building up a list element by element. For example, we might be looking for all months with an r in them. Typically we would compute that by working our way through each month m, checking to see if there is an r in m’s name, and if there is, adding m to a result list.

Suppose we had worked our way through the first 4 months and our result list result looked like this:

>>> result
['January', 'February', 'March', 'April']

Here’s what we might do, once we discovered September belongs on the list:

>>> result.append('September')
>>> result
['January', 'February', 'March', 'April', 'September']

This puts September at the end of the list. The following does not do what we want:

>>> result + ['September']
['January', 'February', 'March', 'April','September']
>>> result
['January', 'February', 'March', 'April']

Although concatenating the lists returns the list we want, it does not change the value of result. So this is an important way in which append and concatenation (+) differ. To get what we want using +, we must do:

>>> result = result + ['September']

Although there are occasions when concatenation is convenient (for example, when joining two long lists), it is less efficient than appending.

To place September before the second element of result instead, we could have used insert:

>>> result.insert(1,'September')
>>> result
['January', 'September', 'February', 'March', 'April']

The rule is: Inserting x at index :samp:`i make x the new member with index i. So:

>>> result.insert(len(result),'September')

is equivalent to:

>>> result.append('September')

Finally, we sometimes need to remove things from lists. If we want to remove the last item, a builtin function called pop works:

>>> result
['January', 'February', 'March', 'April', 'September']
>>> result.pop()
'September'
>>> result
['January', 'February', 'March', 'April']

If we want to remove the second item, pop also works:

>>> result
['January', 'February', 'March', 'April', 'September']
>>> result.pop(1)
'February'
>>> result
['January', 'March', 'April', 'September']

If we want to remove a specific item whose position is unknown, we use remove:

>>> result
['January', 'February', 'March', 'April', 'September']
>>> result.remove('February')
>>> result
['January', 'March', 'April', 'September']

Now let’s say we have a list of months we want to remove something from, and we know two things. We know the element we want to remove is ‘September’ and we know it’s the last thing on the list. Which method should we use, remove or pop? Or does it matter?

It matters little in this instance, but in principle we should use pop. It’s more efficient. The first thing remove has to do is to search through the list to find where in it ‘September’ occurs. Only then can it perform the right update on the list. This could take quite a while if, say, the list, is 1,000,000 elements long and ‘September’ is the last thing on it. Meanwhile, pop involves no search. It just removes the element at a particular index.

3.4.1.5. Methods versus functions and operators: A brief digression

Readers new to programming languages and programming may wonder about the peculiar syntax used with append, insert and remove. For example, rather than calling append with the usual Python function syntax, append(L,'September'), it is called with the list argument L written first followed by ., followed by the rest of the arguments in the usual parentheses. This is because append is a list method rather than a function. The idea of a method is that it is a function which has a natural affinity to a particular type or class, with the possibility that it is implemented specifically for that type or class. For example, lists are mutable sequences, and appending is a natural operation for a mutable sequence because order is meaningful and it is natural that adding elements to the end of sequence will be meaningful (for example, when building the sequence by iterating through another sequence). Other natural mutable sequence operations are inserting elements at a particular position (index), finding the position of a particular element, counting the number of times a particular element appears, reversing the sequence, and sorting. In fact, all of these, along with a few others, are implemented as methods on lists, as shown in the list of list methods at the end of this section. This is not counting the sequence operations that we normally write with a different syntax, such as retrieving a value by position L[index] or updating a value by position L[index] = x, or testing whether a sequence contains a particular element x in L or concatenating two sequences L + M to create a third. In fact, these operations all call special double underscore methods (sometimes call dunder methods): L.__get_item__(…), L.__set_item__(...), L.__contains__(...), and L.__add__(...) defined for lists. We reserve more detailed discussion of methods for a later chapter when we have introduced classes. For now, as far as lists go, we simply state that it is part of what it means to be a list to have all the above-mentioned methods defined. More generally, methods, at least as they are usually conceived, are functions that implement the fundamental computational operations for a class or type conceived for a particular computational purpose.

3.4.1.6. List operators, methods, and functions

In all the following examples, L is a list. Many of the following operators, methods, and functions are covered in the discussions above. A few are new, but useful.

len(L)

Returns length of L.

x in L

Returns True if x is in L. Otherwise returns False.

L.insert(i, x)

Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).

L.append(x)

Equivalent to a.insert(len(a), x).

L.index(x)

Return the index in L for the first occurrence of x. It is a ValueError if x is not a member of L.

L.remove(x)

Remove the first occurrence of x from L. It is a ValueError if x is not a member of L.

L.sort()

Sort the items of the list. Much more to be said about this. But it sorts inplace, meaning it permanently alters the order of elements in L.

L.reverse()

Reverse the elements of the list, in place.

L.count(x)

Return the number of times x appears in the list.

See also

Beginners will find Enthought’s introductory lectures on Python, entitled Python Essentials, very useful. Users with an Academic license have free access to these lectures. For a alternative nice overview of list operations, see the Google’s tutorial. This is geared toward the more advanced student. For a real programmer’s discussion of Python lists, addressing questions like what’s faster, assignment or insertion, or what’s faster, insertion at the beginning, or insertion at the end, see Fredrik Lundh’s effbot.org discussion.