Discover Python, Part 4: Explore the Python type hierarchy

Using lists

Python provides a number of useful features, of which the list class is one of the most important. This article introduces the list class and demonstrates some of the many ways in which you can use it to simplify difficult programming tasks.

Share:

Robert Brunner, NCSA Research Scientist, Assistant Professor of Astronomy, University of Illinois, Urbana-Champaign

Robert J. BrunnerRobert 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 rb@ncsa.uiuc.edu.



30 August 2005

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 tuple and 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.

The Python list

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 list in Python
>>> 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 = [1]    # 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 list class.

Listing 2. Getting help for the list
>>> 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 len method.

Listing 3. Creating a list object directly
>>> 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 list constructor.

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 list
>>> l = list([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

>>> l[0]         # Get the first item in the list

0

>>> type(l[0])

<type 'int'>

>>> l[5]         # 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[0], l[1], l[2]    

(0, 1, 2)

As you learned in the previous articles, slicing is an extremely powerful concept. The general form is l[start:end:step], where start and 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 l[0::2].


A mutable sequence

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 list
>>> l = []

>>> l[0] = 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

[0]

>>> l[0] = 1

>>> l

[1]

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.

A heterogeneous mutable sequence

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 tuple, 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 list
>>> l=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> l

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> l[2] = 2

>>> type(l[2])

<type 'int'>

>>> l[2] = "two"      # Change the type of an element

>>> type(l[2])

<type 'str'>

>>> l

[0, 1, 'two', 3, 4, 5, 6, 7, 8, 9]

>>> l[2] = l[2:5] * 2 

>>> l

[0, 1, ['two', 3, 4, 'two', 3, 4], 3, 4, 5, 6, 7, 8, 9]

>>> del(l[2])         # 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 list.

An array

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 list as an array
>>> al = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

>>> al

[[0, 1, 2], [3, 4, 5], [6, 7, 8]]

>>> al[0][0]          # First element in 2D array

0

>>> al[2][2]          # Last element in 2D array

8

>>> al[1][2]

5

>>> al = [[[0, 1], [2, 3]], [[4, 5], [6, 7]]]

>>> al

[[[0, 1], [2, 3]], [[4, 5], [6, 7]]]

>>> al[0][0][1]

1

>>> len(al)           # Length of outer dimension

2

>>> len(al[0])        # Length of middle dimension

2

>>> len(al[0][0])     # Length of inner dimension

2

Other list operations

The 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.

A list can also be used to emulate other data structures in addition to an array. For example, the append and 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 list
>>> 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]

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]

The list: It slices and dices

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.

Resources

Learn

  • 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 tuple class 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

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=92993
ArticleTitle=Discover Python, Part 4: Explore the Python type hierarchy
publish-date=08302005