The list class is a fundamental built-in data type in Python. It has an impressive and useful set of features, allowing you to efficiently organize and manipulate heterogeneous data. Knowing how to use lists is a must-have skill for you as a Python developer. Lists have many use cases, so you’ll frequently reach for them in real-world coding.
By working through this tutorial, you’ll dive deep into lists and get a solid understanding of their key features. This knowledge will allow you to write more effective code by taking advantage of lists.
In this tutorial, you’ll learn how to:
- Create new lists in Python
- Access the items in an existing list
- Copy, update, grow, shrink, and concatenate existing lists
- Sort, reverse, and traverse existing lists
- Use other features of Python lists
In addition, you’ll code some examples that showcase common use cases of lists in Python. They’ll help you understand how to better use lists in your code.
To get the most out of this tutorial, you should have a good understanding of core Python concepts, including variables, functions, and for loops. You’ll also benefit from familiarity with other built-in data types, such as strings, tuples, dictionaries, and sets.
Free Bonus: Click here to download the sample code that will make you an expert on Python’s list data type.
Getting Started With Python’s list Data Type
Python’s list is a flexible, versatile, powerful, and popular built-in data type. It allows you to create variable-length and mutable sequences of objects. In a list, you can store objects of any type. You can also mix objects of different types within the same list, although list elements often share the same type.
Note: Throughout this tutorial, you’ll use the terms items, elements, and values interchangeably to refer to the objects stored in a list.
Some of the more relevant characteristics of list objects include being:
- Ordered: They contain elements or items that are sequentially arranged according to their specific insertion order.
- Zero-based: They allow you to access their elements by indices that start from zero.
- Mutable: They support in-place mutations or changes to their contained elements.
- Heterogeneous: They can store objects of different types.
- Growable and dynamic: They can grow or shrink dynamically, which means that they support the addition, insertion, and removal of elements.
- Nestable: They can contain other lists, so you can have lists of lists.
- Iterable: They support iteration, so you can traverse them using a loop or comprehension while you perform operations on each of their elements.
- Sliceable: They support slicing operations, meaning that you can extract a series of elements from them.
- Combinable: They support concatenation operations, so you can combine two or more lists using the concatenation operators.
- Copyable: They allow you to make copies of their content using various techniques.
Lists are sequences of objects. They’re commonly called containers or collections because a single list can contain or collect an arbitrary number of other objects.
Note: In Python, lists support a rich set of operations that are common to all sequence types, including tuples, strings, and ranges. These operations are known as common sequence operations. Throughout this tutorial, you’ll learn about several operations that fall into this category.
In Python, lists are ordered, which means that they keep their elements in the order of insertion:
>>> colors = [
... "red",
... "orange",
... "yellow",
... "green",
... "blue",
... "indigo",
... "violet"
... ]
>>> colors
['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']
The items in this list are strings representing colors. If you access the list object, then you’ll see that the colors keep the same order in which you inserted them into the list. This order remains unchanged during the list’s lifetime unless you perform some mutations on it.
You can access an individual object in a list by its position or index in the sequence. Indices start from zero:
>>> colors[0]
'red'
>>> colors[1]
'orange'
>>> colors[2]
'yellow'
>>> colors[3]
'green'
Positions are numbered from zero to the length of the list minus one. The element at index 0 is the first element in the list, the element at index 1 is the second, and so on.
Lists can contain objects of different types. That’s why lists are heterogeneous collections:
[42, "apple", True, {"name": "John Doe"}, (1, 2, 3), [3.14, 2.78]]
This list contains objects of different data types, including an integer number, string, Boolean value, dictionary, tuple, and another list. Even though this feature of lists may seem cool, in practice you’ll find that lists typically store homogeneous data.
Note: One of the most relevant characteristics of lists is that they’re mutable data types. This feature deeply impacts their behavior and use cases. For example, mutability implies that lists aren’t hashable, so you can’t use them as dictionary keys. You’ll learn a lot about how mutability affects lists throughout this tutorial. So, keep reading!
Okay! That’s enough for a first glance at Python lists. In the rest of this tutorial, you’ll dive deeper into all the above characteristics of lists and more. Are you ready? To kick things off, you’ll start by learning the different ways to create lists.
Constructing Lists in Python
First things first. If you want to use a list to store or collect some data in your code, then you need to create a list object. You’ll find several ways to create lists in Python. That’s one of the features that make lists so versatile and popular.
For example, you can create lists using one of the following tools:
- List literals
- The
list()constructor - A list comprehension
In the following sections, you’ll learn how to use the three tools listed above to create new lists in your code. You’ll start off with list literals.
Creating Lists Through Literals
List literals are probably the most popular way to create a list object in Python. These literals are fairly straightforward. They consist of a pair of square brackets enclosing a comma-separated series of objects.
Here’s the general syntax of a list literal:
[item_0, item_1, ..., item_n]
This syntax creates a list of n items by listing the items in an enclosing pair of square brackets. Note that you don’t have to declare the items’ type or the list’s size beforehand. Remember that lists have a variable size and can store heterogeneous objects.
Here are a few examples of how to use the literal syntax to create new lists:
>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> fruits = ["apple", "banana", "orange", "kiwi", "grape"]
>>> cities = [
... "New York",
... "Los Angeles",
... "Chicago",
... "Houston",
... "Philadelphia"
... ]
>>> matrix = [
... [1, 2, 3],
... [4, 5, 6],
... [7, 8, 9]
... ]
>>> inventory = [
... {"product": "phone", "price": 1000, "quantity": 10},
... {"product": "laptop", "price": 1500, "quantity": 5},
... {"product": "tablet", "price": 500, "quantity": 20}
... ]
>>> functions = [print, len, range, type, enumerate]
>>> empty = []
In these examples, you use the list literal syntax to create lists containing numbers, strings, other lists, dictionaries, and even function objects. As you already know, lists can store any type of object. They can also be empty, like the final list in the above code snippet.
Empty lists are useful in many situations. For example, maybe you want to create a list of objects resulting from computations that run in a loop. The loop will allow you to populate the empty list one element at a time.
Using a list literal is arguably the most common way to create lists. You’ll find these literals in many Python examples and codebases. They come in handy when you have a series of elements with closely related meanings, and you want to pack them into a single data structure.
Note that naming lists as plural nouns is a common practice that improves readability. However, there are situations where you can use collective nouns as well.
For example, you can have a list called people. In this case, every item will be a person. Another example would be a list that represents a table in a database. You can call the list table, and each item will be a row. You’ll find more examples like these in your walk-through of using lists.
Using the list() Constructor
Another tool that allows you to create list objects is the class constructor, list(). You can call this constructor with any iterable object, including other lists, tuples, sets, dictionaries and their components, strings, and many others. You can also call it without any arguments, in which case you’ll get an empty list back.
Here’s the general syntax:
list([iterable])
To create a list, you need to call list() as you’d call any class constructor or function. Note that the square brackets around iterable mean that the argument is optional, so the brackets aren’t part of the syntax. Here are a few examples of how to use the constructor:
>>> list((0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list({"circle", "square", "triangle", "rectangle", "pentagon"})
['square', 'rectangle', 'triangle', 'pentagon', 'circle']
>>> list({"name": "John", "age": 30, "city": "New York"}.items())
[('name', 'John'), ('age', 30), ('city', 'New York')]
>>> list("Pythonista")
['P', 'y', 't', 'h', 'o', 'n', 'i', 's', 't', 'a']
>>> list()
[]
In these examples, you create different lists using the list() constructor, which accepts any type of iterable object, including tuples, dictionaries, strings, and many more. It even accepts sets, in which case you need to remember that sets are unordered data structures, so you won’t be able to predict the final order of items in the resulting list.
Calling list() without an argument creates and returns a new empty list. This way of creating empty lists is less common than using an empty pair of square brackets. However, in some situations, it can make your code more explicit by clearly communicating your intent: creating an empty list.
The list() constructor is especially useful when you need to create a list out of an iterator object. For example, say that you have a generator function that yields numbers from the Fibonacci sequence on demand, and you need to store the first ten numbers in a list.
In this case, you can use list() as in the code below:
>>> def fibonacci_generator(stop):
... current_fib, next_fib = 0, 1
... for _ in range(0, stop):
... fib_number = current_fib
... current_fib, next_fib = next_fib, current_fib + next_fib
... yield fib_number
...
>>> fibonacci_generator(10)
<generator object fibonacci_generator at 0x10692f3d0>
>>> list(fibonacci_generator(10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Calling fibonacci_generator() directly returns a generator iterator object that allows you to iterate over the numbers in the Fibonacci sequence up to the index of your choice. However, you don’t need an iterator in your code. You need a list. A quick way to get that list is to wrap the iterator in a call to list(), as you did in the final example.
This technique comes in handy when you’re working with functions that return iterators, and you want to construct a list object out of the items that the iterator yields. The list() constructor will consume the iterator, build your list, and return it back to you.
Note: You can also use the literal syntax and the iterable unpacking operator (*) as an alternative to the list() constructor.
Here’s how:
>>> [*fibonacci_generator(10)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
In this example, the iterable unpacking operator consumes the iterator, and the square brackets build the final list of numbers. However, this technique is less readable and explicit than using list().
As a side note, you’ll often find that built-in and third-party functions return iterators. Functions like reversed(), enumerate(), map(), and filter() are good examples of this practice. It’s less common to find functions that directly return list objects, but the built-in sorted() function is one example. It takes an iterable as an argument and returns a list of sorted items.
Building Lists With List Comprehensions
List comprehensions are one of the most distinctive features of Python. They’re quite popular in the Python community, so you’ll likely find them all around. List comprehensions allow you to quickly create and transform lists using a syntax that mimics a for loop but in a single line of code.
The core syntax of list comprehensions looks something like this:
[expression(item) for item in iterable]
Every list comprehension needs at least three components:
expression()is a Python expression that returns a concrete value, and most of the time, that value depends onitem. Note that it doesn’t have to be a function.itemis the current object fromiterable.iterablecan be any Python iterable object, such as a list, tuple, set, string, or generator.
The for construct iterates over the items in iterable, while expression(item) provides the corresponding list item that results from running the comprehension.
To illustrate how list comprehensions allow you to create new lists out of existing iterables, say that you want to construct a list with the square values of the first ten integer numbers. In this case, you can write the following comprehension:
>>> [number ** 2 for number in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
In this example, you use range() to get the first ten integer numbers. The comprehension iterates over them while computing the square and building the new list. This example is just a quick sample of what you can do with a list comprehension.
Note: To dive deeper into list comprehensions and how to use them, check out When to Use a List Comprehension in Python.
In general, you’ll use a list comprehension when you need to create a list of transformed values out of an existing iterable. Comprehensions are a great tool that you need to master as a Python developer. They’re optimized for performance and are quick to write.
Accessing Items in a List: Indexing
You can access individual items from a list using the item’s associated index. What’s an item’s index? Each item in a list has an index that specifies its position in the list. Indices are integer numbers that start at 0 and go up to the number of items in the list minus 1.
To access a list item through its index, you use the following syntax:
list_object[index]
This construct is known as an indexing operation, and the [index] part is known as the indexing operator. It consists of a pair of square brackets enclosing the desired or target index. You can read this construct as from list_object give me the item at index.
Here’s how this syntax works in practice:
>>> languages = ["Python", "Java", "JavaScript", "C++", "Go", "Rust"]
>>> languages[0]
'Python'
>>> languages[1]
'Java'
>>> languages[2]
'JavaScript'
>>> languages[3]
'C++'
>>> languages[4]
'Go'
>>> languages[5]
'Rust'
Indexing your list with different indices gives you direct access to the underlying items. If you use the Big O notation for time complexity, then you can say that indexing is an O(1) operation. This means that lists are quite good for those situations where you need to access random items from a series of items.
Here’s a more visual representation of how indices map to items in a list:
"Python" |
"Java" |
"JavaScript" |
"C++" |
"Go" |
"Rust" |
|---|---|---|---|---|---|
0 |
1 |
2 |
3 |
4 |
5 |
In any Python list, the index of the first item is 0, the index of the second item is 1, and so on. The index of the last item is the number of items minus 1.
The number of items in a list is known as the list’s length. You can check the length of a list by using the built-in len() function:
>>> len(