This is a surprisingly common question.
They both behave in a very similar way.
Both lists and tuples are sequence data types that can store a collection of items.
Each item stored in a list or a tuple can be of any data type.
And you can also access any item by its index.
So the question is, are they different at all?
And if not, why do we have two data types that behave pretty much in the same way?
Can’t we just live with either lists or tuples?
Well let’s try to find the answer.
The Key Difference between a List and a Tuple
The main difference between lists and a tuples is the fact that lists are mutable whereas tuples are immutable.
What does that even mean, you say?
A mutable data type means that a python object of this type can be modified.
An immutable object can’t.
Let’s see what this means in action.
Let’s create a list and assign it to a variable.
>>> a = ["apples", "bananas", "oranges"]
Now let’s see what happens when we try to modify the first item of the list.
Let’s change “apples” to “berries”.
>>> a = "berries" >>> a ['berries', 'bananas', 'oranges']
Perfect! the first item of a has changed.
Now what if we want to try the same thing with a tuple instead of a list? Let’s see.
>>> a = ("apples", "bananas", "oranges") >>> a = "berries" Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment
We get an error saying that a tuple object doesn’t support item assignment.
The reason we get this error is because tuple objects, unlike lists, are immutable which means you can’t modify a tuple object after it’s created.
But you might be thinking, Karim, my man, I know you say you can’t do assignment the way you wrote it but how about this? Doesn’t the following code modify a?
>>> a = ("apples", "bananas", "oranges") >>> a = ("berries", "bananas", "oranges") >>> a ('berries', 'bananas', 'oranges')
Let’s see, are we actually modifying the first item in tuple a with the code above?
The answer is No, absolutely not.
To know why, you first have to understand the difference between a variable and a python object.
The Difference Between a Variable and an Object
You are probably confusing variables with objects. This is a very common misconception among beginners.
Remember that a variable is nothing but a reference to the actual python object in memory.
The variable itself is not the object.
For example, let’s try to visualize what happens when you assign a list to a variable a.
>>> a = ["apples", "bananas", "oranges"]
When you do this, a python object of type list is created in the memory and the variable a refers to this object by holding its location in memory.
In fact, you can actually retrieve the location of the list object in memory by inspecting a using the id() function.
>>> a = ["apples", "bananas", "oranges"] >>> id(a) 4340729544
Now if you modify the first index of the list, and check the id() again, you will get the same exact value because a is still referring to the same object.
>>> a = "berries" >>> id(a) 4340729544
The following figure shows exactly what happened after the modification.
Now, let’s see what happens if we perform the same thing on tuples.
>>> a = ("apples", "bananas", "oranges") >>> id(a) 4340765824 >>> a = ("berries", "bananas", "oranges") >>> id(a) 4340765464
As you can see, the two addresses are different.
This means that after the second assignment, a is referring to an entirely new object.
This figure shows exactly what happened.
Moreover, if no other variables in your program is referring to the older tuple then python’s garbage collector will delete the older tuple from the memory completely.
So there you have it, this concept of mutability is the key difference between lists and tuples.
Mutability is not just a python concept, it is a programming language concept that you will encounter in various programming languages.
But now may be this whole discussion evokes another question in your head.
Why do we have mutable and immutable objects?
Why Do we need Mutable and Immutable Objects?
Well actually, they both serve different purposes.
Let’s discuss some of the aspects that differentiate between mutable and immutable objects/
1. Appending Performance
Immutability is more efficient when you know you will be frequently modifying an object.
For example, assume you have some iterable object (say x), and you want to append each element of x to a list.
Of course you can just do L = list(x) but under the hood this transforms into a loop that looks like this:
L =  for item in x: L.append(item)
This works alright. You keep modifying the list object in place until all the elements of x exist in the list L.
But can you even imagine what would happen if we had used a tuple instead?
T = () for item in x: T = T + (item,)
Can you visualize what is happening in the memory?
Since tuples are immutable, you are basically copying the contents of the tuple T to a new tuple object at EACH iteration.
If your for loop is big, this is a huge performance problem.
Actually, let’s use python to measure the performance of appending to a list vs appending to a tuple when x = range(10000).
$ python3 -m timeit \ -s "L = " \ -s "x = range(10000)" \ "for item in x:" " L.append(item)" 1000 loops, best of 3: 1.08 msec per loop
Cool, 1.08 milliseconds.
How about if we do the same thing with tuples?
$ python3 -m timeit \ -s "T = ()" -s "x = range(10000)" \ "for item in x:" " T = T + (item,)" 10 loops, best of 3: 1.63 sec per loop
A whopping 1.63 seconds!
This is a huge performance difference between lists and tuples.
If you want to test your patience, try x = range(1000000).
Now when someone tells you multiple appending to a string object is inefficient, you will understand exactly why (string objects are immutable too in python).
Appending performance: Mutability Wins!
2. Easiness of Debugging
Mutability is cool and all but one thing that can be really annoying with mutable objects is debugging.
What do I mean by that?
Let’s take a look at this very simple example.
>>> a = [1, 3, 5, 7] >>> b = a >>> b = -10 >>> a [-10, 3, 5, 7]
Notice that when we do b = a, we are not copying the list object from b to a.
We are actually telling python that the two variables a and b should reference the same list object.
Because a effectively holds the location of the python object in memory, when you say b = a you copy that address location (not the actual object) to b.
This results in having two references (a and b) to the same list object.
In other words when we do b = -10, it has the same effect as a = -10.
Of course you can look at the code and rightfully think that it is easy to debug.
Well you are right for small snippets of code like this, but imagine if you have a big project with many references to the same mutable object.
It will be very challenging to track all the changes to this object because any modification by any of those references will modify the object.
This is not the case with immutable objects even if you have multiple references to them.
Once an immutable object is created, its content will never change.
Easiness of debugging: Immutability Wins!
3. Memory Efficiency
Another benefit of immutability is that it allows the implementation of the language to be more memory efficient.
Let me explain what I mean by that.
In CPython (the most popular implementation of Python) if you create immutable objects that hold the same value, python (under certain conditions) might bundle these different objects into one.
For example, take a look at this code:
>>> a = "Karim" >>> b = "Karim" >>> id(a) 4364823608 >>> id(b) 4364823608
Remember that Strings (as well as Integers, Floats, and Bools) are all examples of immutable objects as well.
As you can see, even though in our python program we explicitly created two different string objects, python internally bundled them into one.
How did we know that?
Well because the identity of a is exactly the same as the identity of b.
Python was able to do that because the immutability of strings makes it safe to perform this bundling.
Not only that this will save us some memory (by not storing the string multiple times in memory), but also every time you want to create a new object with the same value, python will just create a reference to the object that already exists in memory which is definitely more efficient.
Not only strings, this also applies to integers (under certain conditions).
>>> a = 1 >>> b = 1 >>> id(a) 4305324416 >>> id(b) 4305324416
That’s pretty cool, isn’t it?
What about tuples though?
CPython until python 3.6 has made the design decision not to automatically bundle two equivalent tuples into one.
>>> a = (1, 2) >>> b = (1, 2) >>> id(a) 4364806856 >>> id(b) 4364806920
As you can see, a has a different identity than b.
This design decision makes sense because performing interning for tuples requires making sure that all the tuple items are themselves immutable.
Memory efficiency: Immutability Wins
To understand the difference between python lists and tuples, you must understand the concept of mutability/immutability first.
Lists are mutable objects which means you can modify a list object after it has been created.
Tuples on the other hand are immutable objects which means you can’t modify a tuple object after it’s been created.
Both Mutability and Immutability have their own advantages and disadvantages.
If you are a beginner, then I highly recommend this book.
No longer a beginner?
Then you are ready for this book to get to the next level (It’s my favorite).