By Naomi Ceder

Understanding how list indices and lists work in Python makes the language a lot more useful. This article excerpt discusses list indices and modifying lists in Python.

Save 37% off The Quick Python Book, Third Edition with code fccceder at manning.com.


List indices

Understanding how list indices work makes Python much more useful.

Elements can be extracted from a Python list using a notation like C’s array indexing. Like C and many other languages, Python starts counting from zero; asking for element zero returns the first element of the list, asking for element one returns the second element, and so forth. Here are a few examples:

 
>>> x = ["first", "second", "third", "fourth"]
>>> x[0]
'first'

>>> x[2]
'third'
 

But Python indexing is more flexible than C indexing; if indices are negative numbers, they indicate positions counting from the end of the list, with negative one being the last position in the list, negative two being the second-to-last position, and so forth. Continuing with the same list x, we can do the following:

 
>>> a = x[-1]
>>> a
'fourth'
>>> x[-2]
'third'
 

For operations involving a single list index, it’s generally satisfactory to think of the index as pointing at a specific element in the list. For more advanced operations, it’s more correct to think of list indices as indicating positions between elements. In the list ["first", "second", "third", "fourth"], you can think of the indices as pointing like this:

x =[ “first”, “second”, “third”, “fourth” ]
Positive indices 0 1 2 3
Negative indices –4 –3 –2 –1

This is irrelevant when you’re extracting a single element, but Python can extract or assign to an entire sublist at once – an operation known as slicing. Instead of entering list[index] to extract the item after index, enter list[index1:index2] to extract all items including index1 and up to (but not including) index2 into a new list. Here are some examples:

 
>>> x = ["first", "second", "third", "fourth"]   
>>> x[1:-1]
['second', 'third']
>>> x[0:3]
['first', 'second', 'third']
>>> x[-2:-1]
['third']
 

It may seem reasonable that if the second index indicates a position in the list before the first index, this would return the elements between those indices in reverse order, but this isn’t what happens. Instead, this returns an empty list:

 
>>> x[-1:2]
[]
 

When slicing a list, it’s also possible to leave out index1 or index2. Leaving out index1 means “go from the beginning of the list,” and leaving out index2 means “go to the end of the list”:

 
>>> x[:3]
['first', 'second', 'third']
>>> x[2:]
['third', 'fourth']
 

Omitting both indices makes a new list that goes from the beginning to the end of the original list; it copies the list. This is useful when you wish to make a copy that you can modify, without affecting the original list:

 
>>> y = x[:]
>>> y[0] = '1 st'
>>> y
['1 st', 'second', 'third', 'fourth']
>>> x
['first', 'second', 'third', 'fourth']
 

Try This: list slices and indexes

Using what you know about the len() function and list slices, how would you combine the two to get the second half of a list when you don’t know what size the list is? Experiment in the Python shell to confirm if your solution works.

Modifying lists

You can use list index notation to modify a list as well as to extract an element from it. Put the index on the left side of the assignment operator:

 
>>> x = [1, 2, 3, 4]
>>> x[1] = "two"
>>> x
[1, 'two', 3, 4]
 

Slice notation can be used here too. Saying something like lista[index1:index2] = listb causes all elements of lista between index1 and index2 to be replaced with the elements in listb. listb can have more or fewer elements than are removed from lista, in which case the length of lista is altered. You can use slice assignment to do several different things, as shown here:

 
>>> x = [1, 2, 3, 4]
>>> x[len(x):] = [5, 6, 7]                
>>> x
[1, 2, 3, 4, 5, 6, 7]
>>> x[:0] = [-1, 0]                       
>>> x
[-1, 0, 1, 2, 3, 4, 5, 6, 7]
>>> x[1:-1] = []                          
>>> x
[-1, 7]
 

❶   Appends list to end of list

  Appends list to front of list

  Removes elements from list

Appending a single element to a list is such a common operation that there’s a special append method to do it:

 
>>> x = [1, 2, 3]
>>> x.append("four")
>>> x
[1, 2, 3, 'four']
 

One problem can occur if you try to append one list to another. The list gets appended as a single element of the main list:

 
>>> x = [1, 2, 3, 4]
>>> y = [5, 6, 7]
>>> x.append(y) 
>>> x
[1, 2, 3, 4, [5, 6, 7]]
 

The extend method is like the append method, except that it allows you to add one list to another:

 
>>> x = [1, 2, 3, 4]
>>> y = [5, 6, 7]
>>> x.extend(y) 
>>> x
[1, 2, 3, 4, 5, 6, 7]
 

A special insert method allows you to insert new list elements between two existing elements or at the front of the list. insert is used as a method of lists and takes two additional arguments; the first is the index position in the list where the new element should be inserted, and the second is the new element itself:

 
>>> x = [1, 2, 3]
>>> x.insert(2, "hello")
>>> print(x)
[1, 2, 'hello', 3]
>>> x.insert(0, "start")
>>> print(x)
['start', 1, 2, 'hello', 3]
 

insert understands list indices in its own way, but for most uses it’s easiest to think of list.insert(n, elem) as meaning insert elem prior to the nth element of list. insert is a convenience method. Anything that can be done with insert can also be done using slice assignment; list.insert(n, elem) is the same thing as list[n:n] = [elem] when n is non-negative. Using insert makes for more readable code, and insert even handles negative indices:

 
>>> x = [1, 2, 3]
 
>>> x.insert(-1, "hello")
 
>>> print(x)
 
[1, 2, 'hello', 3]
 

The del statement is the preferred method of deleting list items or slices. It doesn’t do anything that can’t be done with slice assignment, but it’s usually easier to remember and easier to read:

 
>>> x = ['a', 2, 'c', 7, 9, 11]
>>> del x[1]
>>> x
['a', 'c', 7, 9, 11]
>>> del x[:2]
>>> x
[7, 9, 11]
 

In general, del list[n] does the same thing as list[n:n+1] = [], whereas del list[m:n] does the same thing as list[m:n] = [].

The remove method isn’t the converse of insert. Whereas insert inserts an element at a specified location, remove looks for the first instance of a given value in a list and removes that value from the list:

 
>>> x = [1, 2, 3, 4, 3, 5]
>>> x.remove(3)
>>> x
[1, 2, 4, 3, 5]
>>> x.remove(3)
>>> x
[1, 2, 4, 5]
>>> x.remove(3)
Traceback (innermost last):
 File "<stdin>", line 1, in ?
ValueError: list.remove(x): x not in list
 

If remove can’t find anything to remove, it raises an error. You can catch this error using the exception-handling abilities of Python, or you can avoid the problem by using in to check for the presence of something in a list before attempting to remove it.

The reverse method is a more specialized list modification method. It efficiently reverses a list in place:

 
>>> x = [1, 3, 5, 6, 7]
>>> x.reverse()
>>> x
[7, 6, 5, 3, 1]
 
Try this: Modifying lists

Suppose you have a list which is ten items long. How might you move last three items from the end of the list to the beginning, keeping them in the same order?

That’s all for lists! For more, download the free first chapter of The Quick Python Book, Third Edition and see this Slideshare Presentation.