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.
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
ifx
is inL
. Otherwise returnsFalse
.
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, anda.insert(len(a), x)
is equivalent toa.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.