Lists vs Tuples in Python – Real Python
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Lists and Tuples in Python
In Python, lists and tuples are versatile and useful data types that allow you to store data in a sequence. You’ll find them in virtually every nontrivial Python program. Learning about them is a core skill for you as a Python developer.
In this tutorial, you’ll:
- Get to know lists and tuples
- Explore the core characteristics of lists and tuples
- Learn how to define and manipulate lists and tuples
- Decide when to use lists or tuples in your code
To get the most out of this tutorial, you should know the basics of Python programming, including how to define variables.
Take the Quiz: Test your knowledge with our interactive “Lists vs Tuples in Python” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Lists vs Tuples in Python
Challenge yourself with this quiz to evaluate and deepen your understanding of Python lists and tuples. You’ll explore key concepts, such as how to create, access, and manipulate these data types, while also learning best practices for using them efficiently in your code.
Getting Started With Python Lists and Tuples
In Python, a list is a collection of arbitrary objects, somewhat akin to an array in many other programming languages but more flexible. To define a list, you typically enclose a comma-separated sequence of objects in square brackets ([]
), as shown below:
In this code snippet, you define a list of colors using string objects separated by commas and enclose them in square brackets.
Similarly, tuples are also collections of arbitrary objects. To define a tuple, you’ll enclose a comma-separated sequence of objects in parentheses (()
), as shown below:
In this example, you define a tuple with data for a given person, including their name, age, job, and base country.
Up to this point, it may seem that lists and tuples are mostly the same. However, there’s an important difference:
Feature | List | Tuple |
---|---|---|
Is an ordered sequence | ✅ | ✅ |
Can contain arbitrary objects | ✅ | ✅ |
Can be indexed and sliced | ✅ | ✅ |
Can be nested | ✅ | ✅ |
Is mutable | ✅ | ❌ |
Both lists and tuples are sequence data types, which means they can contain objects arranged in order. You can access those objects using an integer index that represents their position in the sequence.
Even though both data types can contain arbitrary and heterogeneous objects, you’ll commonly use lists to store homogeneous objects and tuples to store heterogeneous objects.
Note: In this tutorial, you’ll see the terms homogeneous and heterogeneous used to express the following ideas:
- Homogeneous: Objects of the same data type or the same semantic meaning, like a series of animals, fruits, colors, and so on.
- Heterogeneous: Objects of different data types or different semantic meanings, like the attributes of a car: model, color, make, year, fuel type, and so on.
You can perform indexing and slicing operations on both lists and tuples. You can also have nested lists and nested tuples or a combination of them, like a list of tuples.
The most notable difference between lists and tuples is that lists are mutable, while tuples are immutable. This feature distinguishes them and drives their specific use cases.
Essentially, a list doesn’t have a fixed length since it’s mutable. Therefore, it’s natural to use homogeneous elements to have some structure in the list. A tuple, on the other hand, has a fixed length so the position of elements can have meaning, supporting heterogeneous data.
Creating Lists in Python
In many situations, you’ll define a list
object using a literal. A list literal is a comma-separated sequence of objects enclosed in square brackets:
In this example, you create a list of countries represented by string objects. Because lists are ordered sequences, the values retain the insertion order.
Alternatively, you can create new lists using the list()
constructor:
In this example, you use the list()
constructor to define a list of digits using a range
object. In general, list()
can convert any iterable to a list.
You can also create new list
objects using list comprehensions. For example, the following comprehension builds a list of even digits:
List comprehensions are powerful tools for creating lists in Python. You’ll often find them in Python code that runs transformations over sequences of data.
Finally, to create an empty list, you can use either an empty pair of square brackets or the list()
constructor without arguments:
The first approach is arguably the most efficient and most commonly used. However, the second approach can be more explicit and readable in some situations.
Creating Tuples in Python
Similar to lists, you’ll often create new tuples using literals. Here’s a short example showing a tuple definition:
In this example, you create a tuple containing the parameters for a database connection. The data includes the server name, port, timeout, and database name.
Strictly speaking, to define a tuple, you don’t need the parentheses. The comma-separated sequence will be enough:
In practice, you can define tuples without using a pair of parentheses. However, using the parentheses is a common practice because it improves the readability of your code.
Because the parentheses are optional, to define a single-item tuple, you need to use a comma:
In the first example, you create a tuple containing a single value by appending a comma after the value. In the second example, you use the parentheses without the comma. In this case, you create an integer value instead of a tuple.
You can also create new tuples using the tuple()
constructor:
In this example, you create a list of digits using tuple()
. This way of creating tuples can be helpful when you’re working with iterators and need to convert them into tuples.
Finally, to create empty tuples, you can use a pair of parentheses or call tuple()
without arguments:
The first approach is a common way to create empty tuples. However, using tuple()
can be more explicit and readable.
Exploring Core Features of Lists and Tuples
Now that you know the basics of creating lists and tuples in Python, you’re ready to explore their most relevant features and characteristics. In the following section, you’ll dive into these features and learn how they can impact the use cases of lists and tuples in your Python code.
Lists and Tuples Are Ordered Sequences
List and tuples are ordered sequences of objects. The order in which you insert the objects when you create a list or tuple is an innate characteristic. This order remains the same for that list or tuple’s lifetime:
In these examples, you can confirm that the order of items in lists and tuples is the same order you define when creating the list or tuple.
Lists and Tuples Can Contain Arbitrary Objects
Lists and tuples can contain any Python objects. The elements of a list or tuple can all be the same type:
In these examples, you create a list of integer numbers and then a tuple of similar objects. In both cases, the contained objects have the same data type. So, they’re homogeneous.
The elements of a list or tuple can also be of heterogeneous data types:
Here, your list and tuple contain objects of different types, including strings, integers, Booleans, and floats. So, your list and tuple are heterogeneous.
Note: Even though lists and tuples can contain heterogeneous or homogeneous objects, the common practice is to use lists for homogeneous objects and tuples for heterogeneous objects.
Lists and tuples can even contain objects like functions, classes, and modules:
In these examples, the list and the tuple contain a class, built-in function, custom function, and module objects.
Lists and tuples can contain any number of objects, from zero to as many as your computer’s memory allows. In the following code, you have a list and tuple built out of a range with a million numbers:
These two lines of code will take some time to run and populate your screen with many, many numbers.
Finally, objects in a list or tuple don’t need to be unique. A given object can appear multiple times:
Lists and tuples can contain duplicated values like "bark"
in the above examples.
Lists and Tuples Can Be Indexed and Sliced
You can access individual elements in a list or tuple using the item’s index in square brackets. This is exactly analogous to accessing individual characters in a string. List indexing is zero-based, as it is with strings.
Consider the following list:
The indices for the elements in words
are shown below:
Here’s the Python code to access individual elements of words
:
The first element in the list has an index of 0
. The second element has an index of 1
, and so on. Virtually everything about indexing works the same for tuples.
You can also use a negative index, in which case the count starts from the end of the list:
Index -1
corresponds to the last element in the list, while the first element is -len(words)
, as shown below:
Slicing also works with lists and tuples. For example, the expression words[m:n]
returns the portion of words
from index m
to, but not including, index n
:
Other features of slicing work for lists as well. For example, you can use both positive and negative indices:
Omitting the first index starts the slice at the beginning of the list or tuple. Omitting the second index extends the slice to the end of the list or tuple:
You can specify a stride—either positive or negative:
The slicing operator ([:]
) works for both lists and tuples. You can check it out by turning words
into a tuple and running the same slicing operations on it.
Lists and Tuples Can Be Nested
You’ve seen that an element in a list or tuple can be of any type. This means that they can contain other lists or tuples. For example, a list can contain sublists, which can contain other sublists, and so on, to arbitrary depth.
Consider the following example:
The internal structure of this list is represented in the diagram below:
In this diagram, x[0]
, x[2]
, and x[4]
are strings, each one character long:
However, x[1]
and x[3]
are sublists or nested lists:
To access the items in a sublist, append an additional index:
Here, x[1][1]
is yet another sublist, so adding one more index accesses its elements:
There’s no limit to the depth you can nest lists this way. However, deeply nested lists or tuples can be hard to decipher in an indexing or slicing context.
Lists Are Mutable, Tuples Are Immutable
The built-in list
class provides a mutable data type. Being mutable means that once you create a list
object, you can add, delete, shift, and move elements around at will. Python provides many ways to modify lists, as you’ll learn in a moment. Unlike lists, tuples are immutable, meaning that you can’t change a tuple once it has been created.
You can replace or update a value in a list by indexing it on the left side of an assignment statement:
In this example, you create a list of letters where some letters are in uppercase while others are in lowercase. You use an assignment to turn the lowercase letters into uppercase letters.
Now, because tuples are immutable, you can’t do with a tuple what you did in the above example with a list:
If you try to update the value of a tuple element, you get a TypeError
exception because tuples are immutable, and this type of operation isn’t allowed for them.
You can also use the del
statement to delete individual items from a list. However, that operation won’t work on tuples:
You can remove individual elements from lists using the del
statement because lists are mutable, but this won’t work with tuples because they’re immutable.
What if you want to change several elements in a list at once? Python allows this operation with a slice assignment, which has the following syntax:
Think of an iterable as a container of multiple values like a list or tuple. This assignment replaces the specified slice of a_list
with the content of <iterable>
:
In this example, you replace the 0
values with the corresponding consecutive numbers using a slice assignment.
It’s important to note that the number of elements to insert doesn’t need to be equal to the number of elements in the slice. Python grows or shrinks the list as needed. For example, you can insert multiple elements in place of a single element:
In this example, you replace the 7
with a list of values from 4
to 7
. Note how Python automatically grows the list for you.
You can also insert elements into a list without removing anything. To do this, you can specify a slice of the form [n:n]
at the desired index:
In this example, you insert the desired values at index 3
. Because you’re using an empty slice, Python doesn’t replace any of the existing values. Instead, it makes space for the new values as needed.
You can’t do slice assignment on tuple
objects:
Because tuples are immutable, they don’t support slice assignment. If you try to do it, then you get a TypeError
exception.
Lists Have Mutator Methods, Tuples Don’t
Python lists have several methods that you can use to modify the underlying list. These methods aren’t available for tuples because tuples are immutable, so you can’t change them in place.
In this section, you’ll explore the mutator methods available in Python list
objects. These methods are handy in many situations, so they’re great tools for you as a Python developer.
.append(obj)
The .append(obj)
method appends an object to the end of a list as a single item:
In this example, you append the letter "c"
at the end of a
using the .append()
method, which modifies the list in place.
Note: List mutator methods modify the target list in place. They don’t return a new list:
In this code, you grab the return value of .append()
in x
. Using the print()
function, you can uncover that the value is None
instead of a new list
object. While this behavior is deliberate to make it clear that the method mutates the object in place, it can be a common source of confusion when you’re starting to learn Python.
If you use an iterable as an argument to .append()
, then that iterable is added as a single object:
This call to .append()
adds the input list of letters as it is instead of appending three individual letters at the end of a
. Therefore, the final list has three elements—the two initial strings and one list object. This may not be what you intended if you wanted to grow the list with the contents of the iterable.
.extend(iterable)
The .extend()
method also adds items to the end of a list. However, the argument is expected to be an iterable like another list. The items in the input iterable
are added as individual values:
The .extend()
method behaves like the concatenation operator (+
). More precisely, since it modifies the list in place, it behaves like the augmented concatenation operator (+=
). Here’s an example:
The augmented concatenation operator produces the same result as .extend()
, adding individual items at the end of the target list.
.insert(index, obj)
The .insert()
method inserts the input object into the target list at the position specified by index
. Following the method call, a[<index>]
is <obj>
, and the remaining list elements are pushed to the right:
In this example, you insert the letter "b"
between "a"
and "c"
using .insert()
. Note that just like .append()
, the .insert()
method inserts the input object as a single element in the target list.
.remove(obj)
The .remove()
method removes the input object from a list. If obj
isn’t in the target list, then you get a ValueError
exception:
With .remove()
, you can delete specific objects from a given list. Note that this method removes only one instance of the input object. If the object is duplicated, then only its first instance will be deleted.
.pop([index=-1])
The .pop()
method also allows you to remove items from a list. It differs from .remove()
in two aspects:
- It takes the index of the object to remove rather than the object itself.
- It returns the value of the removed object.
Calling .pop()
without arguments removes and returns the last item in the list:
If you specify the optional index
argument, then the item at that index is removed and returned. Note that index
can be negative too:
The index
argument defaults to -1
, so a.pop(-1)
is equivalent to a.pop()
.
Using Operators and Built-in Functions With Lists and Tuples
Several Python operators and built-in functions also work with lists and tuples. For example, the in
and not in
operators allow you to run membership tests on lists:
The in
operator returns True
if the target object is in the list and False
otherwise. The not in
operator produces the opposite result.
The concatenation (+
) and repetition (*
) operators also work with lists and tuples:
You can also use the built-in len()
, min()
, max()
, and sum()
functions with lists and tuples:
In this example, the len()
function returns the number of values in the list. The min()
and max()
functions return the minimum and maximum values in the list, respectively. The sum()
function returns the sum of the values in the input list.
Finally, it’s important to note that all these functions work the same with tuples. So, instead of using them with list
objects, you can also use tuple
objects.
Packing and Unpacking Lists and Tuples
A tuple literal can contain several items that you typically assign to a single variable or name:
When this occurs, it’s as though the items in the tuple have been packed into the object, as shown in the diagram below:
If the packed objects are assigned to a tuple of names, then the individual objects are unpacked as shown in the diagram below, where you use a tuple of s*
variables:
Here’s how this unpacking works in Python code:
Note how each variable receives a single value from the unpacked tuple. When you’re unpacking a tuple, the number of variables on the left must match the number of values in the tuple. Otherwise, you get a ValueError
exception:
In the first example, the number of variables is less than the items in the tuple, and the error message says that there are too many values to unpack. In the second example, the number of variables exceeds the number of items in the tuple. This time, the error message says that there aren’t enough values to unpack.
You can combine packing and unpacking in one statement to run a parallel assignment:
Again, the number of elements in the tuple on the left of the assignment must equal the number on the right. Otherwise, you get an error.
Tuple assignment allows for a curious bit of idiomatic Python. Sometimes, when programming, you have two variables whose values you need to swap. In most programming languages, it’s necessary to store one of the values in a temporary variable while the swap occurs.
Consider the following example that compares swapping with a temporary variable and unpacking:
Using a temporary variable to swap values can be annoying, so it’s great that you can do it with a single unpacking operation in Python. This feature also improves your code’s readability, making it more explicit.
Using Lists vs Tuples in Python
Everything you’ve learned so far about lists and tuples can help you decide when to use a list or a tuple in your code. Here’s a summary of when it would be appropriate to use a list instead of a tuple:
- Mutable collections: When you need to add, remove, or change elements in the collection.
- Dynamic size: When the collection’s size might change during the code’s execution.
- Homogeneous data: When you need to store data of a homogeneous type or when the data represents a homogeneous concept.
Similarly, it’s appropriate to use a tuple rather than a list in the following situations:
- Immutable collections: When you have a fixed collection of items that shouldn’t change, such as coordinates (x, y, z), RGB color values, or other groupings of related values.
- Fixed size: When the collection’s size won’t change during the code’s execution.
- Heterogeneous data: When you need to store data of a heterogeneous type or when the data represents a heterogeneous concept.
- Function’s return values: When a function returns multiple values, you’ll typically use a tuple to pack these values together.
Finally, tuples can be more memory-efficient than lists, especially for large collections where immutability is acceptable or preferred. Similarly, if the integrity of the data is important and should be preserved throughout the program, tuples ensure and communicate that the data must remain unchanged.
Conclusion
Now you know the basic features of Python lists and tuples and understand how to manipulate them in your code. You’ll use these two data types extensively in your Python programming journey.
In this tutorial, you’ve:
- Learned about the built-in lists and tuples data types in Python
- Explored the core features of lists and tuples
- Discovered how to define and manipulate lists and tuples
- Learned when to use lists or tuples in your code
With this knowledge, you can now decide when it’s appropriate to use a list or tuple in your Python code. You also have the essential skills to create and manipulate lists and tuples in Python.
Take the Quiz: Test your knowledge with our interactive “Lists vs Tuples in Python” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Lists vs Tuples in Python
Challenge yourself with this quiz to evaluate and deepen your understanding of Python lists and tuples. You’ll explore key concepts, such as how to create, access, and manipulate these data types, while also learning best practices for using them efficiently in your code.
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Lists and Tuples in Python