Python Simplified

PythonSimplifiedcomLogo

Python List Vs Tuple

Introduction

The lists and tuples need no introduction even for beginners. These two are the commonly used data structures in Python. But what are the similarities and the difference between them, which one should you prefer and when? That’s exactly what we are going to cover in this article – Python List Vs Tuple. Let’s get started.

Similarities

Sequence Type

Both lists and tuples are the sequence data types in which the elements are stored in the form of sequence. The order in which the elements are inserted is maintained and that’s why sequence types are also called ordered sets.

Both lists and tuples support the operations and functions that are common to mutable and immutable types. The common operations are Concatenation, repetition, indexing, and slicing. And the common functions are min, max, len, count, and index.

You may want to take look at our previous article here about sequence type before you continue further.

Homogeneous/Heterogeneous data

Though the lists and tuples are commonly used to hold homogeneous data, they can also contain heterogeneous data meaning they contain different data types as their elements. Refer to the below example that shows lists and tuples can contain both homogeneous and heterogeneous data.

				
					>>> mylist_1 = [10, 20, 30, 40, 50]
>>> mylist_2 = ["Python", "Simplified", ".com"]
>>> mylist_3 = ["Python", "Simplified", [1,2], (3,4)]
>>> mytuple_1 = (10, 20, 30, 40, 50)
>>> mytuple_2 = ("Python", "Simplified", ".com")
>>> mytuple_3 = ("Python", "Simplified", (1,2), [3,4])
				
			

Differences

This section covers in-depth explanations of Python list Vs tuple. For a quick summary of list vs tuple, refer to the table mentioned at the end of this section.

Syntax

A list is a collection of elements enclosed within square brackets [ ] whereas the tuple is enclosed within parenthesis ( )

				
					>>> mylist = [10, 20, 30, 40, 50]
>>> mytuple = (10, 20, 30, 40, 50)
				
			

Mutable Vs. Immutable

This is one of the major differences between a list and a tuple. A list is a mutable object whereas a tuple is an immutable object. Mutable means once the object is created its contents can be changed (insert, modify or delete). In the case of immutable objects, their contents can’t be modified once created. 

Refer to the below list example where the contents of the list are changed. Since lists are mutable objects, we are allowed to modify their contents. 

				
					>>> mylist_1 = [10, 20, 30, 40, 50]
>>> mylist_1.append(60)
>>> mylist_1[0] = 100
>>> del mylist_1[-1]
>>> mylist_1
[100, 20, 30, 40, 50]
				
			

On the other hand, since tuples are immutable objects, you are not allowed to change their contents. Otherwise, you will run into TypeError as you can see below.

				
					>>> mytuple_1 = (10, 20, 30, 40, 50)
>>> mytuple_1[0] = 100
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
				
			

If you need to refresh your knowledge on mutability and immutability in Python, you can go through this article. 

Built-in Methods

Since the list is a mutable object, we can insert, delete or modify its contents. Hence list comes with a lot of built-in methods such as — insert, pop, remove, sort, sorted, reverse etc. 

On the other hand, a tuple supports only a couple of built-in methods because a tuple is immutable. Since you are not allowed to modify the immutable object, it makes sense that tuple doesn’t have many built-in functions.

You can run dir(list) and dir(tuple) to see the supported built-in functions for both list and tuple.

				
					>>> dir(list)
>>> dir(tuple)
				
			

Storage Efficiency

Tuples are more storage efficient than lists. This is better understood in action. 

List: You already know that a list is a mutable object. When you are appending elements to the list, Python over-allocates the memory at a specific interval (this interval is decided by an algorithm that you don’t have to worry about)

				
					prev = 56
mylist_1 = []
print(f"No. of elements: {0}, size: {sys.getsizeof(mylist_1)}, Diff: {0}")

for num in range(1, 20):
    mylist_1.append(num)
    temp_size = sys.getsizeof(mylist_1)
    diff, prev = temp_size - prev, temp_size
    print(f"No. of elements: {num}, size: {temp_size}, Diff: {diff}")
				
			

This code outputs the below details. As you can see, an empty list takes 56 bytes. But when you append an element to an empty list, Python allocates 32 bytes. But as you can see, Python is allocating 24 bytes extra (over allocates) instead of 8 bytes that are needed for one element. The same over-allocation happens when appending the 5th, 9th, and 17th elements to the list and so on. This interval is decided by an algorithm.

				
					No. of elements: 0, size: 56, Diff: 0
No. of elements: 1, size: 88, Diff: 32
No. of elements: 2, size: 88, Diff: 0
No. of elements: 3, size: 88, Diff: 0
No. of elements: 4, size: 88, Diff: 0
No. of elements: 5, size: 120, Diff: 32
No. of elements: 6, size: 120, Diff: 0
No. of elements: 7, size: 120, Diff: 0
No. of elements: 8, size: 120, Diff: 0
No. of elements: 9, size: 184, Diff: 64
No. of elements: 10, size: 184, Diff: 0
No. of elements: 11, size: 184, Diff: 0
No. of elements: 12, size: 184, Diff: 0
No. of elements: 13, size: 184, Diff: 0
No. of elements: 14, size: 184, Diff: 0
No. of elements: 15, size: 184, Diff: 0
No. of elements: 16, size: 184, Diff: 0
No. of elements: 17, size: 256, Diff: 72
No. of elements: 18, size: 256, Diff: 0
No. of elements: 19, size: 256, Diff: 0
No. of elements: 20, size: 256, Diff: 0
				
			

Also, note that there is a difference between creating a list with 20 elements at once and appending 20 elements one by one. Refer to the below code for the difference in memory allocation:

				
					>>> sys.getsizeof(mylist_1)
256

>>> mylist_2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
>>> sys.getsizeof(mylist_2)
216
				
			

Tuple: Since tuples are immutable you won’t be able to change their content. However, if you create a tuple by increasing one element at a time and check the tuple size, you will notice that there is always a difference of 8 bytes. 

				
					prev = 0
mytuple = ()
print(f"No. of elements: {0}, size: {sys.getsizeof(my_tuple)}, Diff: {0}")

for i in range(1, 11):
    my_tuple = tuple(range(1, i+1))
    tuple_size = sys.getsizeof(my_tuple)
    diff, prev = tuple_size - prev, tuple_size
    print(f"No. of elements: {i}, size: {tuple_size}, Diff: {diff}")
				
			

Output:

				
					No. of elements: 0, size: 40, Diff: 0
No. of elements: 1, size: 48, Diff: 48
No. of elements: 2, size: 56, Diff: 8
No. of elements: 3, size: 64, Diff: 8
No. of elements: 4, size: 72, Diff: 8
No. of elements: 5, size: 80, Diff: 8
No. of elements: 6, size: 88, Diff: 8
No. of elements: 7, size: 96, Diff: 8
No. of elements: 8, size: 104, Diff: 8
No. of elements: 9, size: 112, Diff: 8
No. of elements: 10, size: 120, Diff: 8
				
			

If you were to convert the above mylist_1 a tuple, the size will now get reduced from 256 bytes to 200 bytes as you can see below. 

				
					>>> mytuple_1 = tuple(mylist_1)
>>> sys.getsizeof(mytuple_1)
200
				
			

Time Efficiency

Creation of list & tuple: The creation of a tuple is faster than a list. In the below example, we have used timeit module to see how much time it takes to create a list and a tuple 10 Million times. The result clearly shows that the tuple is the winner.

				
					>>> timeit("(1,2,3,4,5,6,7,8,9,10)", number=10_000_000)
0.20845220000046538

>>> timeit("[1,2,3,4,5,6,7,8,9,10]", number=10_000_000)
1.319473100000323
				
			

Accessing the elements: Even accessing the elements from the tuple is faster than accessing the list. Though there will not be much difference, still a tuple is a winner. This is because tuples have direct pointers to their elements, whereas the list uses another intermediate array that contains pointers to the elements in the list.

				
					>>> my_tuple = tuple(range(100_000))
>>> my_list = list(my_tuple)

>>> timeit("my_tuple[99_999]", globals=globals(), number=10_000_000)
0.7667628999988665

>>> timeit("my_list[99_999]", globals=globals(), number=10_000_000)
0.7837690000014845
				
			

Curious to know why the tuple creation and accessing the tuple elements is faster than the list? To prove this, we will be using the dis module. The dis module disassembles classes, methods, functions, and other compiled objects and outputs the bytecode that is used by the Python compiler. 

In the below example, we will use two functions my_list and my_tuple. Both the functions create a list or tuple and access an element. Next, we use the dis module on both the functions to see how many byte code instructions are needed. 

				
					from dis import dis

def my_list():
    x = [10, 20, 30, 'abc']
    y = x[0]

def my_tuple():
    x = (10, 20, 30, 'abc')
    y = x[0]

dis(my_list)
dis(my_tuple)
				
			

The output of dis(my_list): The list creation and accessing list element generate around 6 byte-code instructions each.

				
					2            0 LOAD_CONST              1 (10)
             2 LOAD_CONST              2 (20)
             4 LOAD_CONST              3 (30)
             6 LOAD_CONST              4 ('abc')
             8 BUILD_LIST              4
            10 STORE_FAST              0 (x)

3           12 LOAD_FAST               0 (x)
            14 LOAD_CONST              5 (0)
            16 BINARY_SUBSCR
            18 STORE_FAST              1 (y)
            20 LOAD_CONST              0 (None)
            22 RETURN_VALUE
				
			

The output of dis(my_tuple): The tuple creation requires only 2 instructions. This is because of Python’s peephole optimization. Since the number of instructions is less, obviously tuple creation is faster than a list. But accessing the tuple element creates similar instructions. So, based on the other factors we may see that accessing tuple elements may be faster than list as we saw in the previous example with the timeit function.

				
					6            0 LOAD_CONST               1 ((10, 20, 30, 'abc'))
             2 STORE_FAST               0 (x)

7            4 LOAD_FAST                0 (x)
             6 LOAD_CONST               2 (0)
             8 BINARY_SUBSCR
            10 STORE_FAST               1 (y)
            12 LOAD_CONST               0 (None)
            14 RETURN_VALUE
				
			
list vs tuple table
Python list vs tuple: differences

So, who is the winner?

Based on your understanding of list vs. tuple so far, what do you think? Well, it depends

If the contents of the sequence (list or tuple) don’t change during the program’s lifetime, you should consider using a tuple otherwise consider list. Another way of saying this is that if you are just iterating over the sequence, you should use a tuple. This provides write protection.

Conclusion

In this article, we went through one of the common questions among Python developers i.e list vs tuple. We first discussed the similarities between and list and tuple and then differences between list vs tuple in great detail. At last, we concluded that tuple is the winner in all fonts (speed, storage, etc.). However, the choice between list and tuple depends on the use-case. 

Hope you find this article interesting and gained something from it. If you have any questions please let us know in the comments below.

Share on facebook
Share on twitter
Share on linkedin
Share on whatsapp
Share on email
Chetan Ambi

Chetan Ambi

A Software Engineer & Team Lead with over 10+ years of IT experience, a Technical Blogger with a passion for cutting edge technology. Currently working in the field of Python, Machine Learning & Data Science. Chetan Ambi holds a Bachelor of Engineering Degree in Computer Science.
Scroll to Top