Objective

edit
 
  • Learn about Python lists.
  • Learn about list indexing.
  • Learn about list slicing.
  • Learn how to manipulate a list dynamically.
  • Learn about built-in list functions and methods.
  • Learn when to use lists and when not to.

Lesson

edit

Python Lists

edit

Lists are an important data type that allows you to keep a set of iterable item(s). Lists are mutable sequences. This literally means you can have a list of items, like 1, 2, 3 or "h", "e", "l", "l", "o", "!". A list is denoted by square brackets, []. To create a list that holds actual items, put them within square brackets and use commas to separate the items.

>>> []
[]
>>> [1]
[1]
>>> [1, 2, 3, 4 ,5]
[1, 2, 3, 4, 5]
>>> ["h", "e", "l", "l" ,"o", "!"]
['h', 'e', 'l', 'l', 'o', '!']
>>> [1, 102, 2.22, "F", 2/2, 1+2j, False]
[1, 102, 2.22, 'F', 1.0, (1+2j), False]
>>> list("hello")
['h', 'e', 'l', 'l', 'o']


The built-in function, list() converts a non-list into a list:

>>> a = 'defgh' ; a
'defgh'
>>> b = list(a) ; b
['d', 'e', 'f', 'g', 'h']
>>>
>>> a = b'defgh' ; a
b'defgh'
>>> b = list(a) ; b
[100, 101, 102, 103, 104]
>>> 
>>> list(range(7,13))
[7, 8, 9, 10, 11, 12]
>>>


Lists can also hold multiple different data types, so you can mix numbers, strings, and complexes. Better yet, we can nest lists within each other.

>>> [[1, 2, 3], [2, 1, 3], [True, False, True]]
[[1, 2, 3], [2, 1, 3], [True, False, True]]
>>> [[[[[[1, 2, 3]]]]]]
[[[[[[1, 2, 3]]]]]]
>>> [[[[ 1, 2, [[1, 2, 3]]]]]]
[[[[1, 2, [[1, 2, 3]]]]]]


A list can contain a two-dimensional array:

>>> a = ['a1','a2']
>>> b = ['b1','b2']
>>> c = ['c1','c2']
>>> L = [a,b,c] ; L
[['a1', 'a2'], ['b1', 'b2'], ['c1', 'c2']]
>>> L[0] ; L[1] ; L[2]
['a1', 'a2']
['b1', 'b2']
['c1', 'c2']
>>> L[0][0] ; L[1][1] ; L[2][0]
'a1'
'b2'
'c1'


A list can contain a three-dimensional array:

>>> b = ['b1','b2']
>>> c = ['c1','c2']
>>> d = ['d1','d2']
>>> a = [b,c,d]
>>>
>>> B = ['B1','B2']
>>> C = ['C1','C2']
>>> D = ['D1','D2']
>>> A = [B,C,D]
>>>
>>> array = [a,A]
>>> array
[[['b1', 'b2'], ['c1', 'c2'], ['d1', 'd2']], [['B1', 'B2'], ['C1', 'C2'], ['D1', 'D2']]]
>>>
>>> array[0]
[['b1', 'b2'], ['c1', 'c2'], ['d1', 'd2']]
>>>
>>> array[1]
[['B1', 'B2'], ['C1', 'C2'], ['D1', 'D2']]
>>>
>>> array[1][2]
['D1', 'D2']
>>>
>>> array[1][2][1]
'D2'
>>>


List nesting can get very complicated as the nesting gets deeper, but it creates a great amount of power that will be harnessed in the later parts of this course.

List Indexing

edit

Like strings, lists can be indexed. Indexing can be used to get one item out of the list. For example, if you want to get "o" out of ["h", "e", "l", "l", "o", "!"] type ["h", "e", "l", "l", "o", "!"][4] although, for brevity, we'll put the lists in a variable first. Don't forget that indexing is zero-based in Python.

>>> spam = ["h", "e", "l", "l", "o", "!"]
>>> spam[1]
'e'
>>> spam[5]
'!'
>>> spam[3]
'l'


Like strings, you can index starting with the last item by using a negative number. Don't forget that negative one is the start of the last item, not zero!

>>> spam[-1]
'!'
>>> spam[-3]
'l'
>>> spam[-2]
'o'
>>> spam[-5]
'e'


If you index out of range, by trying to get an item that doesn't exist, you'll get an IndexError.

>>> spam[1000]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> spam[-10]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

List Slicing

edit

Like strings, lists can be sliced. When you slice a list, it will return a new sliced copy of the original list.

>>> spam = [1, 2, 3]
>>> spam[0:3]
[1, 2, 3]
>>> spam[0:]
[1, 2, 3]
>>> spam[1:]
[2, 3]
>>> spam[:1]
[1]
>>> spam[:-1]
[1, 2]
>>> spam[:0]
[]

Lists also support extended slicing, where the third parameter acts as the "step". A step of 1 is the default value.

>>> bacon = ["h", "e", "l", "l", "o", ",", " ", "w", "o", "r", "l", "d", "!"]
>>> bacon[::-1]
['!', 'd', 'l', 'r', 'o', 'w', ' ', ',', 'o', 'l', 'l', 'e', 'h']
>>> bacon[::1]
['h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!']
>>> bacon[::2]
['h', 'l', 'o', ' ', 'o', 'l', '!']
>>> bacon[::-2]
['!', 'l', 'o', ' ', 'o', 'l', 'h']
>>> bacon[::-5]
['!', 'w', 'l']
>>> bacon[:7:-2]
['!', 'l', 'o']

The power of slicing

edit
>>> b = [0,1,2,3,4,5,6] ; b
[0, 1, 2, 3, 4, 5, 6]
>>> b[0:0] = [7,8,9] ; b # insert elements at beginning of list.
[7, 8, 9, 0, 1, 2, 3, 4, 5, 6]
>>> 
>>> b[0:2] = [] ; b # delete elements at beginning of list.
[9, 0, 1, 2, 3, 4, 5, 6]
>>> 
>>> b = [0,1,2,3,4,5,6] ; b
[0, 1, 2, 3, 4, 5, 6]
>>> b += [7,8,9] ; b # add elements at end of list.
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b[-2:] = [] ; b # delete elements at end of list.
[0, 1, 2, 3, 4, 5, 6, 7]
>>> 
>>> b = [0,1,2,3,4,5,6] ; b
[0, 1, 2, 3, 4, 5, 6]
>>> b[2:5] = [7,8,9,10] ; b # modify interior of list
[0, 1, 7, 8, 9, 10, 5, 6]
>>>
>>> # use of brackets '[]':
>>>
>>> b = [[1,2],[3,4],[5,6]] ; b
[[1, 2], [3, 4], [5, 6]]
>>> b[1:2] = [7,8]+[9,10] ; b
[[1, 2], 7, 8, 9, 10, [5, 6]]
>>>
>>> b = [[1,2],[3,4],[5,6]] ; b
[[1, 2], [3, 4], [5, 6]]
>>> b[1:2] = [[7,8]+[9,10]] ; b
[[1, 2], [7, 8, 9, 10], [5, 6]]
>>>
>>> b = [[1,2],[3,4],[5,6]] ; b
[[1, 2], [3, 4], [5, 6]]
>>> b[1:2] = [[7,8],[9,10]] ; b
[[1, 2], [7, 8], [9, 10], [5, 6]]
>>>

List manipulation

edit

Adding a new item to a list is pretty basic. The best way to add a new item is by using the built-in list method append(). This can be easily done as shown below.

>>> spam = [1, 2, 3, 4]
>>> spam.append(5)
>>> spam
[1, 2, 3, 4, 5]
>>> spam.append(12)
>>> spam
[1, 2, 3, 4, 5, 12]
>>> spam.append(6)
>>> spam
[1, 2, 3, 4, 5, 12, 6]

also:

>>> spam = [1,2,3] ; eggs = [8,7,6] ; spam ; eggs
[1, 2, 3]
[8, 7, 6]
>>> spam += eggs ; spam
[1, 2, 3, 8, 7, 6]
>>>


Unlike strings, lists are mutable (can be changed). The best way to change an item in a list is to do so by indexing.

>>> toast = [1, 2, 3]
>>> toast[0] = 100
>>> toast
[100, 2, 3]
>>> toast[1] = 200
>>> toast
[100, 200, 3]
>>> toast[2] = 300
>>> toast
[100, 200, 300]


There are a few ways to remove an item from a list, but because Python culture dictates that there should be one preferable way to do something, I'll give an example that's fast and uses less code.

>>> juice = ["a", "b", "c"]
>>> del juice[1]
>>> juice
['a', 'c']
>>> del juice[0]
>>> juice
['c']
>>> del juice[0]
>>> juice
[]
>>> dog = ["bark", "talk", "beg"]
>>> del dog[:]
>>> dog
[]


You should notice that when you delete an item, the items to the right of the deleted item move over to the left (if possible). So you could keep deleting item zero to remove all of the items. An easier way to delete a whole list is to follow the example with dog. This completely deletes all of the items in the list.



As stated earlier, lists are mutable types, which means their content can dynamically change. Take spam for example. Spam really isn't the list, it just points to the location of the list. Take an address book for another example. It contains the location of a house. It doesn't know what's in the house, it just knows where the house is. spam and the list have the same relationship as the address book and the house.

Now this leads to some important questions, primarily how would you copy spam if it contains the address of the list? Since spam contains the address, giving another variable the same address isn't going to help you.

>>> spam = [1, 2, 3]
>>> eggs = spam
>>> spam
[1, 2, 3]
>>> eggs
[1, 2, 3]
>>> spam[1] = 22
>>> spam
[1, 22, 3]
>>> eggs
[1, 22, 3]


As you can see from the above example, spam and eggs both point to the same list and any change to one affects the other. This is called a shallow copy. If you want two completely different lists, then you create a deep copy. When slicing, the return is always a deep copy, so we could perform a simple slice to create a new list for eggs.

>>> spam = [1, 2, 3]
>>> eggs = spam[:]
>>> spam
[1, 2, 3]
>>> eggs
[1, 2, 3]
>>> spam[1] = 22
>>> spam
[1, 22, 3]
>>> eggs
[1, 2, 3]

This is an important concept to remember early on so you don't run into any problems in the future. While the above example is accurate, it seems to be true only for small lists. NB the following:

Deep copy

edit
>>> b = [  [4, 4, -119, 16], [-1, 1, -1, 1], [0, 14, -17, 0], [1, 1, -13, 1], [2, 4, 8, 16]  ] ; b
[[4, 4, -119, 16], [-1, 1, -1, 1], [0, 14, -17, 0], [1, 1, -13, 1], [2, 4, 8, 16]]
>>>
>>> c = b[:] ; c
[[4, 4, -119, 16], [-1, 1, -1, 1], [0, 14, -17, 0], [1, 1, -13, 1], [2, 4, 8, 16]] # a deep copy of c????
>>> 
>>> b[0][1] = 23 ; b ; c
[[4, 23, -119, 16], [-1, 1, -1, 1], [0, 14, -17, 0], [1, 1, -13, 1], [2, 4, 8, 16]] # both have changed
[[4, 23, -119, 16], [-1, 1, -1, 1], [0, 14, -17, 0], [1, 1, -13, 1], [2, 4, 8, 16]] # not a deep copy
>>>
>>> c = copy.deepcopy(b) ; b ; c
[[4, 23, -119, 16], [-1, 1, -1, 1], [0, 14, -17, 0], [1, 1, -13, 1], [2, 4, 8, 16]]
[[4, 23, -119, 16], [-1, 1, -1, 1], [0, 14, -17, 0], [1, 1, -13, 1], [2, 4, 8, 16]]
>>>
>>> b[1][3] = 23 ; b ; c
[[4, 23, -119, 16], [-1, 1, -1, 23], [0, 14, -17, 0], [1, 1, -13, 1], [2, 4, 8, 16]] # only b has changed
[[4, 23, -119, 16], [-1, 1, -1, 1], [0, 14, -17, 0], [1, 1, -13, 1], [2, 4, 8, 16]] # a true deep copy
>>>

See the reference: " Shallow and deep copy operations"

Built-in List Methods

edit

While the following methods have the appearance of functions and it can be tempting to call them "functions," the correct description is "methods."

list.append(x)

edit

Adds item x to the end of list list.

>>> spam = [1, 2, 3]
>>> spam.append(4)
>>> spam
[1, 2, 3, 4]

equivalent to:

>>> spam = [1, 2, 3]
>>> spam += [4]
>>> spam
[1, 2, 3, 4]

list.clear()

edit

Removes all items from list list.

>>> eggs = [1, 2, 3]
>>> eggs.clear()
>>> eggs
[]

equivalent to:

>>> eggs = [1,2,3] ; eggs
[1, 2, 3]
>>> eggs = [] ; eggs
[]
>>>

list.count(x)

edit

Returns the number of times a given item x is found in list list.

>>> votes = ["yes", "no", "yes", "yes", "no"]
>>> y = votes.count("yes") ; y
3
>>> votes.count("no")
2

list.extend(iterable)

edit

Extend list by appending all items from iterable

>>> bacon = [1, 2, 3]
>>> bacon.extend([4, 5, 6])
>>> bacon
[1, 2, 3, 4, 5, 6]

equivalent to:

>>> bacon = [1, 2, 3]
>>> bacon += [4, 5, 6] ;  bacon
[1, 2, 3, 4, 5, 6]
>>>

list.index(x[, start[, end]])

edit


Finds the first zero-based index of a given item x in list list. The square brackets around [, start[, end]] indicate that these two arguments are optional. start and end are interpreted as in slice notation and are used to limit the search to a particular subsequence of the list.


Case1: list.index(x)

>>> votes = ["yes", "no", "yes", "yes", "no"]
>>> a = votes.index("no") ; a
1
>>> votes.index("yes")
0
>>> votes.index("maybe")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'maybe' is not in list
>>>

Case2: list.index(x, start) equivalent to list[start:].index(x) + start.

>>> votes
['yes', 'no', 'yes', 'yes', 'no']
>>>
>>> votes.index("yes", 1)
2
>>> votes.index("no", 2)
4
>>> votes.index("yes", 4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'yes' is not in list
>>>

Case3: list.index(x, start, end) equivalent to list[start:end].index(x) + start.

>>> votes
['yes', 'no', 'yes', 'yes', 'no']
>>>
>>> votes.index("yes", 1, 3)
2
>>> votes.index("no", 2, 5)
4
>>> votes.index("no", 2, 4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'no' is not in list
>>>

list.insert(i, x)

edit


Inserts item x at position i where i is the zero-based index of the element before which to insert:

>>> jam = [1, 2, 3, 4]
>>> jam.insert(3, 3.5)
>>> jam
[1, 2, 3, 3.5, 4]
>>>

equivalent to :

>>> jam = [1, 2, 3, 4]
>>> jam = jam[:3] + [3.5] + jam[3:] ; jam
[1, 2, 3, 3.5, 4]
>>>

or:

>>> jam = [1,2,3,4] ; jam
[1, 2, 3, 4]
>>> jam[3:3] = [3.5] ; jam
[1, 2, 3, 3.5, 4]
>>>


Out of range:

>>> jam
[1, 2, 3, 3.5, 4, 7]
>>> jam.insert(12,11) ; jam
[1, 2, 3, 3.5, 4, 7, 11] # as in slicing, this doesn't produce an error.
>>>

list.pop([i])

edit


Returns list[i] then deletes list[i]. If optional argument i is not provided i defaults to -1.

>>> toast = [1, 2, 3, 4, 5, 6, 7]
>>> jelly = toast.pop(2) ; jelly ; toast
3
[1, 2, 4, 5, 6, 7]
>>>

equivalent to:

>>> toast = [1, 2, 3, 4, 5, 6, 7]
>>> jelly = toast[2] ; del toast[2] ; jelly ; toast
3
[1, 2, 4, 5, 6, 7]
>>>


>>> toast = [1, 2, 3, 4, 5, 6, 7]
>>> jelly = toast.pop() ; jelly ; toast
7
[1, 2, 3, 4, 5, 6]
>>>

equivalent to:

>>> toast = [1, 2, 3, 4, 5, 6, 7]
>>> jelly = toast[-1] ; del toast[-1] ; jelly ; toast
7
[1, 2, 3, 4, 5, 6]
>>>

list.remove(x)

edit


Remove the first item from list whose value is x. It is an error if there is no such item.

>>> bacon = [1, 2, 3]
>>> bacon.remove(2) # Item removed was not at position 2. It had value 2.
>>> bacon
[1, 3]

list.reverse()

edit


This reverses the order of list in place.

>>> coke = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> coke.reverse()
>>> coke
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>>

equivalent to:

>>> coke = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> coke = coke[::-1] ; coke
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>>

List Usage

edit

Although lists are useful, they are about four to seven times slower than tuples, because lists aren't as static as tuples. Large lists usually have a higher penalty on performance, so try keep them short. As a general rule of thumb, use lists only when you need to dynamically hold information and values.

Using Lists as Stacks

edit

The list methods make it easy to use a list as a stack, where the last element added is the first element retrieved (“last-in, first-out”). To add an item to the top of the stack, use append(). To retrieve an item from the top of the stack, use pop() without an explicit index. For example:

>>> stack = [3, 4, 5]
>>> stack.append(6) # push 6 onto stack
>>> stack += [7]    # push 7 onto stack. 7 is last in.
>>> stack
[3, 4, 5, 6, 7]
>>> stack.pop()
7                   # 7 is first out.
>>> stack
[3, 4, 5, 6]
>>> stack.pop()
6
>>> stack.pop()
5
>>> stack
[3, 4]
>>>

Using Lists as Queues

edit

While lists are not efficient for this purpose, they can be used to illustrate the concept quite well. A queue is a sequence of elements where the first element added is the first element retrieved (“first-in, first-out”).

>>> queue = []                         # empty queue
>>>
>>> queue.append('John') ; queue       # 'John' is first to arrive
['John']
>>> queue += ['Alex'] ; queue          # then 'Alex' arrives and goes to end-of-line.
['John', 'Alex']
>>> queue.append('Terry') ; queue      # then 'Terry' arrives and goes to end-of-line.
['John', 'Alex', 'Terry']
>>>
>>> nextOut = queue[0] ; del queue[0] ; nextOut ; queue # 'John' was first in and first out.
'John'
['Alex', 'Terry']
>>> nextOut = queue.pop(0) ; nextOut ; queue            # 'Alex' was 2nd in and 2nd out.
'Alex'
['Terry']
>>>
>>> queue.append('Graham') ; queue     # then 'Graham' arrives and goes to end-of-line.
['Terry', 'Graham']
>>>

List Comprehensions

edit

List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element satisfies a certain condition applied to each element of a given list.


Given:

>>> a = list(range(-5,7)) ; a
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6]
>>>

List all of the negative numbers in list a:

>>> b = [x for x in a if x < 0] ; b
[-5, -4, -3, -2, -1]
>>>

The above is equivalent to:

>>> b
[]
>>> for x in a :
...     if x < 0 : b += [x]
... 
>>> b
[-5, -4, -3, -2, -1]
>>>


How many floats are there in list a?

>>> len([x for x in a if isinstance(x,float)])
0
>>>


List the position and value of all odd numbers in list a:

>>> [(i,a[i]) for i in range(len(a)) if a[i] % 2]
[(0, -5), (2, -3), (4, -1), (6, 1), (8, 3), (10, 5)]
>>>

Assignments

edit
 
  • Work with some lists. Try creating a list of lists. How could this be used in a real life situation?
  • Work with some of the list's methods. Try them all out at least three times.
  • Does Python lists resemble real life lists? Could it be made into a simple grocery or to do list?

Further Reading or Review

edit
  Completion status: Ready for testing by learners and teachers. Please begin!

References

edit

4. Python's documentation:

"3.1.3. Lists", "4.6.4. Lists", "More on lists", " Shallow and deep copy operations", "The del statement", "Using Lists as Stacks", "Using Lists as Queues", "List Comprehensions", "Common Sequence Operations", "Mutable Sequence Types", "How are lists implemented?"


5. Python's methods:


6. Python's built-in functions:

"class list(iterable)"