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
a + b
yields a Concatenation.a * i
yields Repetition.a[i]
yields Subscription, or the 'i'th element of
'a'.a[i:j:k]
yields Slicing, or a copy of the list 'a'
from its 'i'th element to its (j-1)'th element, taking only every
k'th element. If 'k' is omitted, every element in the range is
taken. If 'i' or 'j' are omitted they default to beginning of list
and end of list respectively.a[:i]
yields a slice from the beginning of 'a' to
the (i-1)'th element of 'a'.a[i:]
yields a slice from the 'i'th element to the
end of the list.a[:]
yields a slice of the entire list. More
importantly it yields a copy of the list!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] >>>
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] >>>
The comparison of lists to other lists, and other types is also slightly different to the comparison of simple types (int, float, bool). Specifically:
a == b
yields Equivalencea < b
yields Less Than. Note that lists are
compared in sequence order, meaning that 'a' is less than 'b' if
'a's first element is less than 'b's first element. If 'a's first
element and 'b's first element are equal, the second elements are
checked, etc...v in a
is True only if the list a contains an
element whose value is that of the expression 'v'.a is b
is True only if 'a' and 'b' are the same
list.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!
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.
a[0] = b
assigns the value of 'b' to the 0'th
element of 'a'. (The mutable type special case applies)a[0:2] = l
removes the slice range specified on
the left and replaces the removed elements with the contents of
'l'. This does not make 'a' and 'l' synonyms.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)
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.
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>.append(<expression>)
>>> a = [] >>> a.append('one') >>> a ['one'] >>>
<list>.count(<expression>)
>>> a = ['a', 'c', 'g', 't', 't', 'a'] >>> a.count('a') 2 >>>
<list>.index(<expression>)
>>> a = ['a', 'c', 'g', 't', 't', 'a'] >>> a.index('t') 3 >>>
<list>.insert(<index expression>, <object
expression>)
>>> a = ['a', 'c', 'g', 't', 't', 'a'] >>> a.insert(2,'newitem') >>> a ['a', 'c', 'newitem', 'g', 't', 't', 'a'] >>>
<list>.pop()
>>> a = ['a', 'c', 'g', 't', 't', 'a'] >>> a.pop() 'a' >>> a ['a', 'c', 'g', 't', 't'] >>>
<list>.remove(<expression>)
>>> a = ['a', 'c', 'newitem', 'g', 't', 't', 'a'] >>> a.remove('newitem') >>> a ['a', 'c', 'g', 't', 't', 'a'] >>>
<list>.reverse()
>>> a = ['alpha', 'beta', 'gamma', 'delta'] >>> a.reverse() >>> a ['delta', 'gamma', 'beta', 'alpha'] >>>
<list>.sort()
>>> a = ['delta', 'gamma', 'beta', 'alpha'] >>> a.sort() >>> a ['alpha', 'beta', 'delta', 'gamma'] >>>
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?
[1, 3] + [2, 4]
?[1, 3] + [[2, 4]]
?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> ##### #### ##### ### # # ###