E-Scribe : a programmer’s blog

About Me

PBX I'm Paul Bissex. I build web applications using open source software, especially Django. Backstory: In the 1990s I did graphic design for newspapers and magazines. Then I wrote technology commentary and reviews for Wired, Salon.com, Chicago Tribune, and lots of little places you've never heard of. Then I taught photographers how to create good websites. I co-wrote a book (see below) along the way. Current story: I am helping turn a giant media corporation into a digital enterprise. Feel free to email me.

Book

I'm co-author of "Python Web Development with Django", an excellent guide to my favorite web framework. Published by Addison-Wesley, it is available from Amazon and your favorite technical bookstore as well.

Colophon

Built using Django, served with gunicorn and nginx. The database is SQLite. Hosted on a FreeBSD VPS at Johncompanies.com. Comment-spam protection by Akismet.

Pile o'Tags

Stuff I Use

bitbucket, Django, Emacs, FreeBSD, Git, jQuery, LaunchBar, Markdown, Mercurial, OS X, Python, Review Board, S3, SQLite, Sublime Text, Ubuntu Linux

Spam Report

At least 231622 pieces of comment spam killed since 2008, mostly via Akismet.

Understanding tuples vs. lists in Python

Python has two seemingly similar sequence types, tuples and lists.

The difference between the two that people notice right away, besides literal syntax (parentheses vs. square brackets), is that tuples are immutable and lists are mutable. Unfortunately, because this distinction is strictly enforced by the Python runtime, some other more interesting differences in application tend to get overshadowed.

One common summary of these more interesting, if subtle, differences is that tuples are heterogeneous and lists are homogeneous. In other words:

What are these "kinds of stuff" I'm talking about? Types? Sometimes. But types may not tell the whole story.

Consider the following two data structures:

>>> import time
>>> time.localtime()
(2008, 2, 5, 11, 55, 34, 1, 36, 0)

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

The first one, a tuple, is a sequence in which position has semantic value. The first position is always a year. This tuple functions as a lightweight record or struct.

The second one, a list, is a sequence where we may care about order, but where the individual values are functionally equivalent.

It's easy to imagine adding or removing items from the second one without breaking code that handles it or creating something undefined; for the first one, not so much.

A great example of the complementary use of both types is the Python DB API's fetchmany() method, which returns the result of a query as a list of tuples. The result set as a whole is a list, because rows are functionally equivalent (homogeneous); the individual rows are tuples, because rows are coherent, record-like groupings of (heterogeneous) column data.

A side note: Many functional languages, including Haskell and OCaml, have a similar distinction that is strictly enforced. Studying one of these languages may help clarify what I'm saying here; it certainly clicked for me when I started playing with Haskell.

There is considerable overlap in the ways tuples and lists can be used, but the built-in capabilities of the two structures highlight some of the above distinctions. For example, tuples have no 'index' method for identifying the position at which a particular value is found.

I've found that keeping the above distinctions in mind has helped me in my Python programming. Hopefully this attempt at clarification will help others too.

Anja Skrba has translated this post into Croatian. Cool!

Tuesday, February 5th, 2008
+ + + +
31 comments

Comment from Lorenzo Bolognini , later that day

The best thing I heard about the distinction of tuples vs. lists is that tuples have identity.

You would use tuples to represent a point (x,y): that alone already gives away the big semantic difference between tuples and lists and helps clarify that they are not just read-only lists.

In Django they're often used to represent, inside a list, an (id, value) pair that you can use in a Select widget.

Have a look at this post and the comment by Jayson Vantuyl.

L.

Comment from Chuck , later that day

The other nice side effect of tuples is that since the are immutable, they can be used as keys in dictionaries.

Comment from Jim Storch , later that day

When people ask me about this I usually start my explanation with this abstraction:

Use a list when you need a bucket to put stuff in; "How can I get all these bricks to the roof?"

Use a tuple when you need a bucket of stuff; "Hope you enjoy this fruit basket."

Comment from Vroo , 2 weeks later

Sorry, this is wrong. Tuples and lists may be either heterogeneous or homogeneous. (1,2), (1,'b'), [1,2] and [1,'b'] are all valid as are things like [1,(2,[3])]. While it may be the case that some developers use tuples for heterogeneous sets and others use lists for homogeneous sets, it's misleading to say that's the difference between the two.

The difference really is that lists are mutable. You can change the values in a list, append to it and delete values in it. You can't do that to a tuple.

Comment from Paul , 2 weeks later

Vroo -- perhaps my use of the word "are" in my third paragraph made things sound too definitive. I'm not claiming to describe "the" difference between the two types; I address the obvious mutable/immutable distinction up front.

What I'm attempting to describe in this post is a common (and in my opinion valuable) convention that is easy to miss when one is first learning Python.

Comment from rae , 18 months later

I think I'm starting to grasp the idea of tuples and lists. This might be a stupid question (I'm a newbie programmer), but I'm a bit confused as to in what conditions would you choose to use tuple over a list (since tuples are immutable, lists sound to be more useful maybe?) Also, you mentioned that tuples can be more efficient, can you give a case for this? Thanks!

Comment from Shaggs , 2 years later

Thanks for the great page. As a C programmer learning python, I found the description given in the page to be very helpful - "I get it"!

Comment from Titus Barik , 2 years later

Looks like one of your links is dead. The link to "Why are there separate tuple and list data types?" now returns a 404.

Comment from Momus , 2 years later

Another case of an explanation which explains nothing.

I believe you that tuples and lists are used most often as you say. But WHY is missing!!

To give a true understanding one must specify how Python deals with those types. My guess (as a 2dn day Python "user"), is that tuples are are stored and/or accessed more efficiently. Which would be a good reason to use them if objects are immutable.

Years ago, when learning C++ I found only one book to be truly useful, by Stroustrup's C++ Reference Manual. Because n the book Stroustrup would give suggestion as to how each feature would be implemented by a compiler. This is the only way to give user a feel of what to use when, when efficiency is a must. And if it's not important then any garbage code will do, as we see all too often...

Comment from Paul , 2 years later

Titus: Thanks for noticing; the passage in question has disappeared from the Python docs, so I've removed the link.

Momus: Welcome to the world of Python! As for the "why" -- in my opinion it's a useful semantic distinction that produces code that's easier to read and maintain. As a bonus, as I suggest above, it also paves the way to experience with interesting functional programming languages like Haskell.

Comment from seb , 2 years later

thanx for the prog definition

Comment from Orhan , 2 years later

A bit confused about tuples not having an index method:

('a', 'b', 'c')[2]

'c'

['a', 'b', 'c'][2]

'c'

Comment from Preston , 2 years later

Orhan, that is not the index method.

['a','b','c'].index('c') 2 ('a','b','c').index('c') Traceback (most recent call last): File "", line 1, in ? AttributeError: 'tuple' object has no attribute 'index'

Comment from kernelmanic , 3 years later

Looks like someone changed their mind:

['a','b','c'].index('c') 2 ('a','b','c').index('c') 2

It seems that everyone who thinks that tuples are just lists with restrictions are either not reading the comments and articles, or they are not realizing that the tuple is simply a heck of a lot of work that is done for you.

It is not a list with restrictions. It is a bunch of code that you would have to write over and over again that is rolled into the base language and given to you as a 'type'.

A tuple allows you to do things that you cant do in lists. You would be required to create your own data structures and objects and methods in order to code the kinds of things that tuples allow you to do.

For example, if you wanted to associate a bunch of textual information for a bunch of people ( say name email phone number etc - for many people ) Now lets say you wanted to access that info using a set of data points. A very silly but workable example:
What if you wanted to separate people ( for marketing purposes perhaps ) based on their answer to the old chat room A/S/L question.

The would be an ever-expanding set of tuples of the form (25, 'F', 'Brooklyn') (21, 'F', 'Osaka' ) which you could easily map to date of birth i.e. (1986, 'F', 'Brooklyn') (1990, 'F', 'Tokyo') You could even add the name of the chat room in the tuple. ;) (1990, 'F', 'Tokyo', '#cowboybebop' ) You could build dictionaries of names and emails and phone numbers - keyed by the tuple corresponding to their A/S/L etc. It is a silly example, but it demonstrates how powerful tuples can be.

If you wanted a to store or access names numbers and email addresses for all girls between 20 and 25 who live in Osaka and hang out in xyz chatroom, you could easily roll up a dictionary to store it. With lists it would be boring. slow, sucky and you would have to deal with irrelevant things like indexes. Or you could roll your own data structure each time. By that time, I would already have the list zapped into my mobile device.... Just sayin.

Comment from vj100 , 3 years later

Tuples in v 3.2.2 do have an index option.

Not sure if this was available in versions prior

Comment from malpaso , 3 years later

As @Vroo notes above it's plain wrong and misleading to say that lists are homogeneous and tuples are heterogeneous. These two statements are completely false:

  • Tuples (generally) are sequences of different kinds of stuff, and you deal with the tuple as a coherent unit.
  • Lists (generally) are sequences of the same kind of stuff, and you deal with the items individually.

It's not a subtle difference either. It's no difference at all. You would serve your readers well if you remove it entirely because you are leading them astray.

Comment from Paul , 3 years later

@malpaso -- I think you misunderstand what I'm trying to say here. I'm not talking about a hard technical difference, I'm talking about a real difference in usage patterns.

As a test of my idea, I'd propose this: from the standard library, pick a random collection of lines that manipulate tuples or lists. Say 10 of each.

Now, are most of the tuples in accord with my statement beginning "Tuples (generally)..."? And are most of the lists in accord with my statement beginning "Lists (generally)..."?

If so, I stand by my point. If not, I'm interested.

Comment from Patrick , 4 years later

Thank you. I am switching to python (from a background in MATLAB and Maple) and wanted you to know how much I appreciate your clear and concise explanation of the topic past the popular "lists are mutable." You may have written this a long time ago, but it made the differences easy to see and is a very useful post.

Comment from zxq9 , 4 years later

There is a lot of argument here, but most of it seems to be because people have grown familiar with the abuse/unthinking use of touples as a data type, not because they grok the difference. A lot of code out there has touples of touples where lists of touples make more sense, both for convenience and semantically -- and perhaps this sort of example could have shed some light on others' misunderstanding.

Using the chat room ASL example above, if I have a bunch of touples with information such as ('32', 'Male', 'Osaka') and ('25', 'Female', 'Texas') most code I see keeps track of this sort of thing by rolling it up into another touple, and sort-of appending by redeclaration via +=

people = (('25', 'Female', 'Texas'), ('32', 'Male', 'Osaka)) people += ((age, sex, location))

Which is not nearly as useful as making people be a list of touples wherein the position of each piece of data is semantically defined and important, but the order of the entries themselves do not have any meaning of its own. And, for the "why doesn't this article discuss language implementation in detail" (despite that explicitely not being the point of a language such as Python...), it just so happens that append() and extend() are more efficient than += on a touple or a list, and considering the use case I would imagine this was intentional.

Comment from Paul , 4 years later

Patrick -- you're welcome! Very glad to hear it was useful to you. That's what I was going for.

zxq9 -- thanks for your comment. I agree, tuples of tuples like that make little sense.

Comment from Zachary Young , 4 years later

Thanks for the write up: it's at least a quick intro to a concept that for me was ambigous, and I got here because I looked up a piece of code I had written 2 months ago that was returning a tuple, and asked, "why a tuple, does a list make more sense?" Either by odds (50/50) or by some other force (had seen some good code somewhere else recently) I think I made the right decision, and your article helped show me that.

Thanks again.

Comment from Paul , 4 years later

Zachary - excellent! Glad to confirm your good instincts.

Comment from dseeking1 , 4 years later

Glad I came across this article (and am surprised that there isn't more on the topic in the web). I'm a telecoms engineer learning Python primarily for my own interests. I now understand how tuples and lists are intended to be used (heterogeneous vs homogeneous) and how this relates to changeability vs unchangeability (mutability vs unmutability). Thanks Paul AND all the other contributors (who clarified the key ideas).

Comment from Kumar , 4 years later

Really great article and very nice comments from readers.... really helped a lot Thank you so much

Comment from jimmy , 4 years later

Thanks for the explanation. I am also learning Python.

It seems that semantics and implicit programming is something that a lot of programmers aren't taught or don't pick up.

When I read a program, I wonder why a programmer chose a specific way of doing something based on their algorithms and data structures, especially if I understand what is supposed to be happening, but I don't understand why.

As you stated above, understanding the semantic differences between different data types is crucial to designing appropriate algorithms. Too many programmers walk around with sledgehammers when a ball peen is all they need, or maybe, even, a rubber mallet.

So what is a Python equivalent to a C structure? I am used to s.a nomenclature to access data out of a structure. You can't do that with a tuple and dictionaries are relatively slow.

So, to use your example, how does the time tuple map to a struct_tm?

Comment from Dobes Vandermeer , 4 years later

Another way of looking at this is that a tuple is supposed to be a sort of "compound value" - it's in the same group as numbers and strings.

A list, on the other hand, is a "container", so it fits in with sets and maps.

Comment from Chirag , 5 years later

This is 5 years old post. My curiosity to know beyond routinely known difference between these two types brought me here.

Your second example doesn't apply to those who have migrated to python 3 because range() returns a memory efficient iterator.

Overall, your article still gives a pragmatic overview on choosing between list and tuples. Makes sense.

Comment from Matt Stevens , 5 years later

Great post, I couldn't understand this concept when I read a few answers on StackOverflow – as soon as you mentioned struct, it all fell into place. Those old days messing around with C sure do come in useful :-).

Comment from Marko Knöbl , 5 years later

Thanks for your explanations - they helped me understand the intended distinction between tuples and lists. (Even if I don't find that distinction very useful)

However, I recently found out that even some builtin functions and classes don't follow this convention:

isinstance(42.0, (int, float)) True isinstance(42.0, [int, float]) TypeError: ...

'mypic.png'.endswith(('.png', '.jpg')) True 'mypic.png'.endswith(['.png', '.jpg']) TypeError: ...

I think that in both cases using a list as the datatype would make more sense with regard to the described convention. Is there any good reason why these functions don't accept lists?

Comment from Marko Knöbl , 5 years later

Oops ... seems like the code I posted was not formatted as intended. Hope it works better now:

isinstance(42.0, (int, float)) True

isinstance(42.0, [int, float]) TypeError:...


'mypic.png'.endswith(('.png', '.jpg')) True

'mypic.png'.endswith(['.png', '.jpg']) TypeError:...

Comment from Bulwinkel , 5 years later

Thank you for this excellent explanation!

Comments are closed for this post.