The second article in this series, "Discover Python, Part 2: Explore the Python type hierarchy, Understanding objects and containers," introduces the Python type hierarchy, which includes container objects. That article demonstrated the
tuple, which is an immutable sequence. The third article in this series, "Exploring the Python type hierarchy, Introducing Strings," introduces the Python
string, which is also an immutable sequence, but only for character data. As immutable sequences, both
string objects can't be modified once they're created. If you need to modify one of them, you must create a new container of the appropriate type to hold the new data. This article introduces a new sequence type: the
list, which is a mutable sequence type that demonstrates a number of different ways it can be used.
When I introduced the Python
tuple, I used the analogy of a bag into which you can throw different items. The Python
list is very similar. As a result, it shares much of the same functionality. One difference, however, is that you can create a
list using square brackets, as shown in Listing 1.
Listing 1. Creating a
>>> l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> type(l) <type 'list'> >>> el =  # Create an empty list >>> len(el) 0 >>> sl =  # Create a single item list >>> len(sl) 1 >>> sl = [1,] # Create a single item list, as with a tuple >>> len(sl) 1
This example shows how to create a simple
list containing the integers from 0 to 9, inclusive, as well as how to create an empty list and a list containing a single item. If you recall, creating a single item
tuple has the complication of requiring a comma following the single item. This is necessary to differentiate the single-item
tuple from a method call, which I'll discuss in detail in a future article. For a
list, this isn't necessary, although using the single comma is allowed.
As always, for more information about a Python topic, you can use the built-in help interpreter. For example, Listing 2 shows the start of the help description for the
Listing 2. Getting help for the
>>> help(list) Help on class list in module __builtin__: class list(object) | list() -> new list | list(sequence) -> new list initialized from sequence's items | | Methods defined here: | | __add__(...) | x.__add__(y) <==> x+y | | __contains__(...) | x.__contains__(y) <==> y in x | ...
If you look closely at the description for the
list class in Listing 2, you'll see that two different constructors are provided. One takes no arguments, and the other takes a sequence class. Thus, you can create a
list using a constructor, in addition to the shorthand notation of using the square brackets. This provides a great deal of flexibility because you can easily convert an existing sequence like a
tuple or a
string into a
list, as shown in Listing 3. Notice, however, that you must pass in a sequence -- and not just a sequence of objects -- or you'll get an error. As with any sequence type, you can easily find out the number of items in the sequence using the
Listing 3. Creating a
>>> l = list() >>> type(l) <type 'list'> >>> len(l) 0 >>> l  >>> l = list((0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) # Create a list from a tuple >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> len(l) 10 >>> l = list([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) # Create a list from a list >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> len(l) 10 >>> l = list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) # Error: Must pass in a sequence Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: list() takes at most 1 argument (10 given) >>> l = list("0123456789") # Create a list from a string >>> l ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] >>> type(l) <type 'list'> >>> len(l) 10
As you can see, it's easy to create a
list, and if you haven't already tried it, now is the time. You aren't limited to passing a sequence directly into the constructor; you can also pass a variable that holds a tuple or a string into the
Obviously, the main reason sequences are useful is that it's easy to access the items in the sequence. If you remember from the
tuple discussion, you can access items from a sequence one item at a time or by slicing items. The same techniques work with the Python
list, as shown in Listing 4.
Listing 4. Accessing items from a
>>> l = list([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> l # Get the first item in the list 0 >>> type(l) <type 'int'> >>> l # Get the sixth item in the list 5 >>> l[1:5] # Get the second through fifth items [1, 2, 3, 4] >>> type(l[1:5]) <type 'list'> >>> l[0::2] # Get every second item [0, 2, 4, 6, 8] >>> l, l, l (0, 1, 2)
As you learned in the previous articles, slicing is an extremely powerful concept. The general form is
end are the starting and ending indexes, respectively, and
step is the number of items to step over when slicing. You can also use negative values for the ending index, which counts back from the end of the sequence. Another useful feature is that errors -- such as exceeding the length of the sequence -- are generally handled in a graceful manner. As shown in the previous example, you can also choose to omit one or more of the three values used in slicing. For example, I left off the ending index of the slice
At the start of this article, I mentioned that the main difference between the
list and the
tuple is that the
list is a mutable sequence. This means you can not only access the items in a
list easily but also modify them easily. This introduces a complication: You can only modify items in a sequence. To add items to a sequence (not just modify items), you can use the
append method, as shown in Listing 5.
Listing 5. Modifying a
>>> l =  >>> l = 0 # The list is empty Traceback (most recent call last): File "<stdin>", line 1, in ? IndexError: list assignment index out of range >>> l.append(0) >>> l  >>> l = 1 >>> l 
As the previous example demonstrated, trying to modify a
list item that doesn't exist results in an error. This makes sense and demonstrates the Python approach to generating errors. When something is serious, an error is raised. If the issue is minor and can be easily handled, then it is.
You may wonder about more complex modifications. By combining what you know about slicing with the knowledge that a
list can be modified, you've gained a significant insight: You can modify a list in a number of ways. And just like a
list can hold different types of data (or different types of objects). This is what I mean by a heterogeneous mutable sequence. Both of these capabilities are demonstrated more fully in Listing 6.
Listing 6. A heterogeneous mutable
>>> l=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> l = 2 >>> type(l) <type 'int'> >>> l = "two" # Change the type of an element >>> type(l) <type 'str'> >>> l [0, 1, 'two', 3, 4, 5, 6, 7, 8, 9] >>> l = l[2:5] * 2 >>> l [0, 1, ['two', 3, 4, 'two', 3, 4], 3, 4, 5, 6, 7, 8, 9] >>> del(l) # Remove single element >>> l [0, 1, 3, 4, 5, 6, 7, 8, 9] >>> l[1:3] =  # Remove a slice >>> l [0, 4, 5, 6, 7, 8, 9]
Modifying an item within a
list is rather simple: You set the item's value appropriately, even to a different type, such as a
string or another
list. You can also use the repeat operator, which you may recognize as the multiplication operator, to build up a bigger list from small segments.
The previous examples have shown you how to add an element to a
list and how to modify an item in a
list. The previous example also demonstrates how to delete objects from a
list. The first method for deleting items is to use the
del method. This method can be used to delete one item or a range of items. You can also use the power and flexibility of slicing to delete slices from a
In the previous example, you saw that a
list can contain another
list as an item. If you extend this example, you may wonder what happens if every item is replaced by a
list. The result is an array -- or, for the more mathematically inclined, a matrix. Listing 7 shows how to use a
list to hold a two-dimensional (2-D) or three-dimensional (3-D) array.
Listing 7. The
listas an array
>>> al = [[0, 1, 2], [3, 4, 5], [6, 7, 8]] >>> al [[0, 1, 2], [3, 4, 5], [6, 7, 8]] >>> al # First element in 2D array 0 >>> al # Last element in 2D array 8 >>> al 5 >>> al = [[[0, 1], [2, 3]], [[4, 5], [6, 7]]] >>> al [[[0, 1], [2, 3]], [[4, 5], [6, 7]]] >>> al 1 >>> len(al) # Length of outer dimension 2 >>> len(al) # Length of middle dimension 2 >>> len(al) # Length of inner dimension 2
list object has a number of useful methods that can be applied to an existing list. For example, you can reverse all the items in a
list or sort a
list. An important point to remember with these operations, however, is that they operate in place, which means they modify the
list on which they're called. So, if you try to create a new list and set it to be the result of a call to one of these methods, you'll get an empty list.
list can also be used to emulate other data structures in addition to an array. For example, the
pop methods operating on a
list function as either a First In, First Out (FIFO) data structure, also known as a queue; or as a Last In, First Out (LIFO) data structure, also known as a stack. The
pop method supports these capabilities by allowing you to set the item to be popped (removed and returned) from the
list. If you pop the first item of a
list, you have a queue; whereas, if you pop the last item of a
list, you have a stack, as shown in Listing 8.
Listing 8. Manipulating a
>>> l=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> id(l) # This is the object id for our current list 4525432 >>> l.reverse() # Reverse the list >>> l [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>> id(l) # The id is the same, modified list in place. 4525432 >>> l.sort() # Sort the list in numerical order >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> id(l) # Modified the existing list 4525432 >>> l.index(5) # Same as l 5 >>> l.count(0) # How many times does '0' occur in the list 1 >>> l.pop() # Take off the last item (Stack) 9 >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8] >>> l.pop(5) # Take out the fifth element 5 >>> l [0, 1, 2, 3, 4, 6, 7, 8] >>> l.pop(0) # Take the first item off the list (Queue) 0 >>> l [1, 2, 3, 4, 6, 7, 8]
This article introduced the
list, which is a container object that can be easily modified and that can hold different types of data. Given this flexibility, it isn't surprising that the
list is one of the most-used constructs in the Python programming language. You can use the
list like a bag to hold different types of data that can be changed at will. You can use the
list like an array to hold data in an organized manner. And you can use the
list as a queue or as a stack. Future articles will explore this flexibility in greater detail, and introduce a powerful programming technique known as list comprehensions.
This series starts with "Discover Python, Part 1: Python's built-in numerical types."
Part 2 of this series discusses the object nature of the language, initially for the built-in simple types. The Python
tupleclass is introduced and used to demonstrate the concept of a container type.
Part 3 of this series introduces the string class and demonstrates different ways in which you can use a string within Python.
IBM developerWorks has published many articles on Python, including the Charming Python series by David Mertz.
If you prefer to use an IDE, read the developerWorks article "Python development with Eclipse and Ant" by Ron Smith, which shows how to use Eclipse to write Python code.
The Python Reference Manual provides a discussion of the object nature of Python.
When you have a working Python interpreter, the Python tutorial is a great place to start learning the language.
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
Get products and technologies
Download Python from Python.org.
Get evaluation products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere® and start building applications and deploying them on IBM middleware.
Select the Linux® or Windows® version of the Software Evaluation Kit (SEK).
Innovate your next open source development project with
IBM trial software, available for download or on DVD.
Get involved in the developerWorks community by participating in developerWorks blogs.
Robert J. Brunner is a Research Scientist at the National Center for Supercomputing Applications and an Assistant Professor of Astronomy at the University of Illinois, Urbana-Champaign. He has published several books and a number of articles and tutorials on a range of topics. You can reach him at email@example.com.