Introductory Programming in Python: Lesson 9
Lists

[Prev: Flow Control: Sequential Loops] [Course Outline] [Next: Tuples]

Lists in Detail

We've already learnt a little about about lists, but there are many more features to lists, and sadly a few intricacies we need to know about. Firstly let's deal more explicitly with the operations that can be performed on lists. If both 'a' and 'b' are lists, 'v' is any expression, and 'i', 'j', and 'k' are integers then

Note that theses operators each return newly created lists, and do not modify the operand lists in any way. For completeness sake, here are examples ...

Python 2.4.3 (#1, Oct	2 2006, 21:50:13) 
[GCC 3.4.6 (Gentoo 3.4.6-r1, ssp-3.4.5-1.0, pie-8.7.9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = [1,2,3]
>>> a+[4,5]
[1, 2, 3, 4, 5]
>>>
>>> [4,5]+a
[4, 5, 1, 2, 3]
>>> a*2
[1, 2, 3, 1, 2, 3]
>>>
>>> [1]*2+2*[2]
[1, 1, 2, 2]
>>>
>>> [[1]*2,[2]*2]
[[1, 1], [2, 2]]
>>>
>>> [1]*2*3
[1, 1, 1, 1, 1, 1]
>>>
>>> a[0]
1
>>> a[1:3]
[2, 3]
>>> a += [4, 5]
>>> a[0:6:2]
[1, 3, 5]
>>> a[:3]
[1, 2, 3]
>>> a[3:]
[4, 5]
>>> a[:]
[1, 2, 3, 4, 5]
>>>

Assignment to elements of a list

Lists are known as mutable objects, in that their value can change. This sounds a little weird, but consider it this way. The value of the integer 1 cannot change. We can change the value indicated by a variable i (which might be 1) to something else, but this doesn't change the value of the integer 1. Lists are different, because the value reflects a container of multiple other values, and we can remove, add, or replace those inner values, i.e. list elements. This changes the value of the list itself. Practically, this means we can assign values to specific elements of a list.

>>> a = [1, 2, 3]
>>> a[0]
1
>>> a[0] = 0
>>> a
[0, 2, 3]
>>> 

Not only can we assign individual elements of a list a new value, but we can assign whole slices new values. The funky thing is, we can replace a specified slice of a list with a list of any length, effectively extending or shrinking the list in the process.

>>> a = [1, 2, 5]
>>> a[1:2] = [3]
>>> a
[1, 3, 5]
>>> a[1:2] = [2, 3, 4]
>>> a
[1, 2, 3, 4, 5]
>>> a[1:4] = [3]
>>> a
[1, 3, 5]
>>> 

Comparing Lists

The comparison of lists to other lists, and other types is also slightly different to the comparison of simple types (int, float, bool). Specifically:

Note the final point, namely the 'is' operator. This is one of those intricacies we mentioned earlier. The 'list' type is what is known as a mutable type, meaning the contents of a list can be changed. This is not true of an integer for example. One cannot change the contents of the integer 1. This introduces a slight complexity. If 'a' is 1 and 'b' is 1 then 'a' and 'b' are the same. But if a = [1], and b = [1], they are not the same. They may be equal, but are not the same list. They are different lists. Again, examples to the rescue

>>> a = [1,2]
>>> b = [1,2]
>>> a == b
True
>>> a is b
False
>>>
>>> b[0] = 3
>>> b
[3, 2]
>>> a
[1, 2]
>>>
>>> a = [1,2]
>>> b = a
>>> a == b
True
>>> a is b
True
>>> b[0] = 3
>>> b
[3, 2]
>>> a
[3, 2]
>>>

Note how the second line of the second example violates our notion of assignment, which was: The assignment statement assigns the value of the expression on the right to the variable on the left. But clearly, we are not just assigning the value ([1,2]), because later when we change the first element of 'b' to 3, we also appear to change the first element of 'a'. Weird. There is a technical explanation for this, but is really not worth knowing at this point as it is more likely to confuse than clarify. What this does mean however is that we need to be aware of the special case of assignment to a single variable of mutable type!

When, in an assignment statement a = b, 'b' is of mutable type, the assignment statement makes 'a' a synonym of 'b', i.e. they become different names for the same variable.

Also note how we assigned a value to an element of the list, changing some of it's contents. Python is quite advanced in terms of how it can handle assignments involving lists, so let's explore its features a bit. If 'a' is the list [1, 2, 3], 'b' is some expression of any value, and 'l' is some expression of type list.

If we wish to make a copy of a list that is not a synonym, we assign to the slice of the full list, e.g. a = b[:] (where 'b' is a list)

Lists as Objects

In addition to the operators that can act on lists, list are objects. Object is a term used in computer science to refer specifically to something which has both code and data associated with it directly. Objects will be covered in far greater detail later on in the course, but in the meanwhile we need to be aware of some syntactical features they provide.

Objects have code associated with them in functions called methods. Methods are bound to every variable of an object type individually, meaning if two different variables, 'a' and 'b', are of the same type which is an object type, then 'a' and 'b' both have the same set of methods but their methods are distinct from one another. When 'a' calls a method, that method acts only on 'a', and when 'b' calls that same method, the method will act only on 'b'. Read it again, it makes sense. In fact examples will prove it's quite intuitive.

>>> a = [1, 2, 3]
>>> b = ["A", "B", "C"]
>>> a.index(2)
1
>>> b.index(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: list.index(x): x not in list
>>> b.index("C")
2
>>> 

Looking at the examples we notice there is some new notation, of the form <list>.<method>(). This 'dot notation' indicates that we are obtaining a method of the list object (called index in the case of the example), and our use of brackets indicates we wish to call it.

Methods are simply functions associated with a particular type.

Note that a.index(2) and b.index(2) return different results. In fact the 'b.index' case produces an error. Obviously they are doing different things, despite being given the same parameter (2). What the index method does is search for a given value in the elements of its list. When called using 'a.index' its list is 'a', when called using 'b.index' its list is 'b'. Since the value 2 is an element of the list 'a', index returns its index position (1), meaning it can be found in the second position in the list. But the value 2 is not an element of the list 'b', hence index will cause an error.

That being said, let's round off our knowledge of lists by enumerating the list methods that will be useful to us.

List Comprehensions

A list comprehension is a special syntactic element of the python language that allows rapid construction of a new list from the elements of an old list. They are a syntactic contraction of the pattern:

new_list = []
for element in old_list:
    new_list.append(<something done with element>)

List comprehensions have the following basic syntax:

[<expression of e> for e in <old_list>]

The list comprehension is an expression itself which evaluates as a list containing the results of the expression of e as each element applied to the e's of the old list. Example time:

Python 2.5.2 (r252:60911, Aug  7 2008, 21:06:43) 
[GCC 4.1.2 (Gentoo 4.1.2 p1.0.2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> [e for e in [2, 4, 5]]
[2, 4, 5]
>>> [2*e for e in [2, 4, 5]]
[4, 8, 10]
>>> [e*e for e in [2, 4, 5]]
[4, 16, 25]
>>> [0 for e in [2, 4, 5]]
[0, 0, 0]
>>> dwarfs = [
... 'Happy',
... 'Grumpy',
... 'Sleepy',
... 'Sneezy',
... 'Doc',
... 'Bashful',
... 'Dopey']
>>> [n.startswith('S') for n in dwarfs]
[False, False, True, True, False, False, False]
>>> [n.endswith('y') for n in dwarfs]
[True, True, True, True, False, False, True]
>>> [[i]*3 for i in range(3)]
[[0, 0, 0], [1, 1, 1], [2, 2, 2]]

Additionally we can select which elements we want to bring in from our old list into our new one using a filter clause.

[<expression of e> for e in <old_list> if <some other expression of e>]

Using a filter clause our new list may not have as many elements as out old list. Let's get only dwarfs names if they start with 'S':

>>> [n for n in dwarfs if n.startswith('S')]
['Sleepy', 'Sneezy']

How cool is this?

Exercises

  1. What is the value of [1, 3] + [2, 4]?
  2. What is the value of [1, 3] + [[2, 4]]?
  3. What is the difference between appending a value to a list and adding the same value within its own list using the concatenation operator?
  4. What is the slice notation to extract the word 'mickles' from the string 'How many mickles are there in a muckle?'
  5. Write a list comprehension that produces a list of 3 lists of length 3, where each inner list starts with an integer one greater than the start of the previous list, and the first list starts at zero.
  6. Write a list comprehension that contains a two element list for each letter of the alphabet, which contains as its first element, the letter of the alphabet, and its second element a boolean value representing whether any of the dwarf names start with that letter.
  7. Modify your answer to question 6 to contain the number of dwarf names beginning with each letter, instead of simply True or False.
  8. Write a program that outputs the position of every 't' in the list ['a', 'c', 'g', 't', 't', 'a', 't']. Use the index method, don't do it manually.
  9. Write a program that asks the user to enter a sequence of up to 5 x:y coordinates with both x and y in the range 0 to 4, ending their sequence entry by providing a blank line for the x coordinate. Then display a five by five grid of '#' characters, with the points in the grid entered by the user left blank. Assume x increases from left to right, and y increases from top to bottom. Example input/output is given ...
    Coordinates range from 0 to 4!
    Please enter pair of coordinates (x:y), leave x blank to terminate sequence.
    X> 3
    Y> 3
    Please enter pair of coordinates (x:y), leave x blank to terminate sequence.
    X> 4
    Y> 1
    Please enter pair of coordinates (x:y), leave x blank to terminate sequence.
    X> 1
    Y> 4
    Please enter pair of coordinates (x:y), leave x blank to terminate sequence.
    X>
    #####
    #### 
    #####
    ### #
    # ###
    
[Prev: Flow Control: Sequential Loops] [Course Outline] [Next: Tuples]