Comprehending Lists and Tuples

Elderly couple, Mr A and Mrs B are staring through french windows at a cat that is sitting in the middle of their lawn motionless and facing away from them. A car is heard drawing up.

The last couple of tutorials have been a bit heavy, so this week’s tutorials are going to balance that out by being a little light. We’re having a look at a couple of different aspects of the Python language.

List Comprehensions
The first is comprehensions:

>>> a_list = [1,2,3,4,5]
>>> b_list= [element*2 for element in a_list]
>>> b_list
[2, 4, 6, 8, 10]

In this example, we have automatically generated a new list b_list from an existing list* a_list by using a list comprehension. The structure of the comprehension is, I hope comprehensible. If not, it is a little hard to explain in steps. The comprehension above is equivalent to:

>>> b_list = []
>>> for element in a_list:
...    b_list.append(element*2)
>>> b_list
[2, 4, 6, 8, 10]

We could call the variable element anything we liked – it is just another variable:

>>> b_list = [baloney*2 for baloney in a_list]
>>> b_list
[2, 4, 6, 8, 10]

You can also add conditions. Let’s say you only wanted the even elements in a_list:

>>> b_list = [element for element in a_list if element%2 ==0] #ie remainder is 0 when dividing by two
>>> b_list
[2, 4]

The condition here is if element%2 ==0, but you can substitute other conditions (as long as they resolve to either True or False). You can have a comprehension which relies on multiple variables (this example is from the Python documentation):

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Unwinding this is a little tricky – for each element in [1,2,3] it runs through each element in [3,1,4] (ie 9 comparisons in all) and appends the tuple if the elements are not equal.

List comprehensions provide an easy shorthand for constructing lists. Moreover, they are often more readable than writing out the for loops explicitly.

The second topic is tuples.
The other thing we’re going to look at is tuples (pronounced, variously, “tupp-lls”, “two-pls” and, to some people, “tyou-pls” – my preference is tupp-lls, rhymes with couples). Tuples are a little like lists, except that they are immutable. That is, once they are made they cannot be changed. Tuples are made by putting the elements in round braces [actually, adding commas between them and, sometimes, also adding braces]:

>>> my_tuple = (1,2,3)
>>> my_tuple
(1, 2, 3)
>>> my_list = [1,2,3]
>>> my_list
[1, 2, 3]

Elements of the tuple are referenced in the same way as you’d reference a list but, unlike lists, these elements cannot be changed (tuples are “immutable”):

Traceback (most recent call last):                                         
  File "<stdin>", line 1, in <module>                                      
TypeError: 'tuple' object does not support item assignment    

The TypeError is telling us that you can’t change the elements of a tuple. To make a tuple with a single element is a little difficult because the interpreter could just interpret the parentheses as determining order of operation (think (1+2)*3). Instead, we put a comma after the single element to indicate that we are creating a tuple:

>>> my_tuple = (1)  # no comma, so Python just thinks it's a number
>>> my_tuple  
>>> my_tuple[0]  # just a number, so has no elements
Traceback (most recent call last):                                                                           
  File "<stdin>", line 1, in <module> 
TypeError: 'int' object has no attribute '__getitem__'
>>> my_tuple= (1,)
>>> my_tuple

So, if a tuple does what a list can do, only less, why bother with a tuple? Why not use a list? Well, tuples are easier for the Python interpreter to deal with and therefore might end up being faster. Tuples might also indicate that you have an ordered list where the ordering has some meaning (for example, a date tuple might store year, month and day (in that order) in tuple). The fact that you’re using a tuple then flags that each of the entries has a distinct meaning or use and that their order is significant. Another pragmatic reason to use a tuple is when you have data which you know shouldn’t change (like a constant). So, if you accidentally try to change one of the tuple’s entries, you will have an error thrown.

Finally, since tuples are immutable they can be used as keys in dictionaries, unlike lists:

>>> my_dict={}
>>> my_tuple=("A Name",23,"A location")
>>> my_list= list(my_tuple)
>>> my_dict[my_tuple]="Client 1"
>>> my_dict[my_list]="Client 2"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

* as per Don’s comment, you can use any iterator, but we haven’t talked about them yet, so they don’t yet exist.

8 Responses to Comprehending Lists and Tuples

  1. Pingback: Python 4 Kids: Comprehending Lists and Tuples | The Black Velvet Room

  2. simple but good one!

  3. Don O'Donnell says:

    You leave the impression that only lists (`a_list`) can be used as a source for comprehensions, whereas any iterator will do such as `xrange()` (Python2) or `range()` (Python3). Also it’s the commas that make a tuple, not the parentheses (or the “round braces” as you call them.):
    >>> my_tuple = 1, 2, 3 # this looks a lot cleaner.
    Parens are only needed to avoid ambiguity as when used in a function call.

  4. Pingback: Links 21/5/2013: Handbrake Turns 0.9.9, NetBSD 6.1 | Techrights

  5. groovy says:

    Can you share performance testing for tupes vs. list?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: