8 – Lists and Tuples

Introduction to Python

Author

Clemens Brunner

Published

February 2, 2026

Creating lists

A list is a container sequence which, unlike strings, can contain items of arbitrary types. We use square brackets to create a new list (with commas separating the list items):

x = [23, "Hello!", "test", 1.44, True]
y = [1, "1", [1, 2, 3], ["test", False, [True, True, 2, 4]]]

Indexing and slicing

Indexing and slicing works exactly like in strings. We use square brackets to extract a single or multiple items from a list:

x[0]
23
x[-2]
1.44
x[1:4]
['Hello!', 'test', 1.44]
x[::-1]
[True, 1.44, 'test', 'Hello!', 23]

Working with lists

Length

The len function returns the number of items in a list:

len(x)
5
len(y)
4

An empty list has a length of zero:

z = []
len(z)
0

Modifying lists

In contrast to strings, lists are mutable. That is, items in a list can be modified after the list has been created. For example:

x
[23, 'Hello!', 'test', 1.44, True]
x[1] = 12345  # no problem here
x
[23, 12345, 'test', 1.44, True]

Remember that we can assign more than one name to a Python object. For example, we could create a second name y for the list that is currently named x:

y = x

If we modify the list, changes are visible through both names x and y, because the underlying list object is one and the same:

x[1] = "Good bye!"
x
[23, 'Good bye!', 'test', 1.44, True]
y
[23, 'Good bye!', 'test', 1.44, True]
Tip

The following example illustrates five options to create a copy of the list x (or in other words, a new list):

x = [1, 2, 3, 4]

x1 = x.copy()
x2 = list(x)
x3 = x[:]

import copy
x4 = copy.copy(x)
x5 = copy.deepcopy(x)

Note that if the list contains mutable objects (such as lists) itself, only copy.deepcopy will create copies from all objects (but this is also the slowest method).

Concatenation

Adding lists with the + operator concatenates their items and creates a new list:

[1, 2, "three"] + ["four", 5, 6.0]
[1, 2, 'three', 'four', 5, 6.0]

Likewise, the * concatenates list items multiple times:

[1.0, 2, "three"] * 3
[1.0, 2, 'three', 1.0, 2, 'three', 1.0, 2, 'three']

List methods

Lists have their own host of methods. Bear in mind that in general, list methods change the given list in place, whereas string methods always create a new string. One of the most frequently used list methods is append, which (as the name implies) appends a new item at the end of the list:

x
[1, 2, 3, 4]
x.append(13)
x
[1, 2, 3, 4, 13]
Important

Because list methods change the list in place, they do not return anything (or rather, they return None). Therefore, the following code will not work as expected:

x = x.append(13)

After this line, x will be None (the return value of append), and the modified list will not be accessible anymore. Therefore, the correct way to append an item to a list is to rely on in-place modification as shown in the previous example.

If we want to append more than one item, we can use the related extend method:

x.extend(["A", "B", "C"])
x
[1, 2, 3, 4, 13, 'A', 'B', 'C']

Note that x.append(["A", "B", "C"]) also works, but produces a different result:

x.append(["A", "B", "C"])
x
[1, 2, 3, 4, 13, 'A', 'B', 'C', ['A', 'B', 'C']]

The del keyword or the pop method both remove items from a list. For example, the following statement removes two items at the given indexes (1 and 2):

del x[1:3]
x
[1, 4, 13, 'A', 'B', 'C', ['A', 'B', 'C']]

Similarly, this is how to remove the last item using pop:

x.pop(-1)
['A', 'B', 'C']
x
[1, 4, 13, 'A', 'B', 'C']

Note that pop returns the removed item and changes the list in place (del does not return anything).

The remove method removes items by value (instead of by index). For example, x.remove(13) removes the first item in the list which is equal to 13:

x.remove(13)
x
[1, 4, 'A', 'B', 'C']

Finally, the sort method sorts a list in place if this is possible. This means that all items should be of the same type, otherwise sorting will result in an error.

x.sort()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[25], line 1
----> 1 x.sort()

TypeError: '<' not supported between instances of 'str' and 'int'

To demonstrate this, let’s create a new list h consisting of only numbers and sort it:

h = [6, 9, 23, 1, -78, 44]
h.sort()
h
[-78, 1, 6, 9, 23, 44]

Iterating over lists

The in keyword checks whether a specific value is contained in a list:

x = [1, 2, 3, 4, 5]
2 in x
True
7 in x
False

Iteration with a for-loop also works as expected:

for item in x:
    print(item)
1
2
3
4
5

Tuples

Tuples are basically immutable lists. We will not go into more detail why tuples are useful, but suffice it to say that we should prefer a tuple instead of a list whenever we do not want to change its items. For example, instead of storing the latitude and longitude of a given location in a list, a tuple might be more reasonable (because the coordinates of a given location will not change).

The syntax for creating a tuple is similar to creating a list, except that it doesn’t use square brackets. Strictly speaking, listing items separated by commas defines a tuple, but sometimes parentheses are required and/or improve readability:

t = 23, "Hello!", "test", 1.44, True
t
(23, 'Hello!', 'test', 1.44, True)

We cannot modify tuples because they are immutable:

t[1]
'Hello!'
t[1] = 12345
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[32], line 1
----> 1 t[1] = 12345

TypeError: 'tuple' object does not support item assignment

List comprehensions

There is another neat way to construct a list in Python: list comprehensions. These do not introduce any new functionality (everything can be accomplished without list comprehensions), but this so-called syntactic sugar makes some list assignments shorter to write and/or easier to read.

Consider the following example, where we want to create a list containing all squares from numbers 1 to 10. We already know how to do this with a for-loop:

squares = []
for n in range(1, 11):
    squares.append(n**2)

The resulting list is:

squares
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

The alternative list comprehension is much more compact and looks as follows:

squares = [n**2 for n in range(1, 11)]
squares
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

In general, a list comprehension is surrounded by square brackets (to denote that a list will be constructed). Inside the brackets, the first expression defines the individual items that go into the new list (n**2 in our example). After that, something very similar to a for-loop iterates over some sequence (some iterable) to generate the individual items (in our case, n takes on values from range(1, 11)).

Here’s another example of a list comprehension, which multiplies each item in a (numeric) list by 2:

numbers = [-4, -2, 0, 2, 4]
numbers2 = [n * 2 for n in numbers]
numbers2
[-8, -4, 0, 4, 8]

Every time we want to apply some operation to each individual item in a list, a list comprehension might be the way to go. Another example is taking the absolute value of each item in a list:

numbers_abs = [abs(x) for x in numbers]
numbers_abs
[4, 2, 0, 2, 4]

Remember that all list comprehensions can be written with a regular loop and the append method. We can also include a condition in the list comprehension, which will include an item in the new list only if the condition is True. This is useful for filtering values as shown in the following example, where we filter all values greater than or equal to zero:

[x for x in numbers if x >= 0]
[0, 2, 4]

List comprehensions can even be nested:

lst = [(x - 1, y - 2) for x in [1, 2, 3] for y in [3, 1, 4] if x != y]
lst
[(0, 1), (0, 2), (1, 1), (1, -1), (1, 2), (2, -1), (2, 2)]

This is a pretty complex list comprehension, and in this case, the traditional way might be more readable:

lst = []  # start with an empty list
for x in [1, 2, 3]:
    for y in [3, 1, 4]:
        if x != y:
            lst.append((x - 1, y - 2))

The results are exactly the same (observe how the individual for and if statements correspond to each other in both list assignments).

Let’s finish up this topic with a slightly less complex list comprehension just to see another example:

freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
[weapon.strip().upper() + "!" for weapon in freshfruit]  # creates a new list
['BANANA!', 'LOGANBERRY!', 'PASSION FRUIT!']

Exercises

  1. Write a function histogram which accepts a list of numbers as its input argument. The function should convert the argument to a simple (vertical) histogram as follows: Each item of the list defines a row in the histogram, the length of which is defined by the value in the list. By default, the histogram should consist of * characters (but it should be possible to change this character with a second argument).

    Here are two examples that demonstrate the behavior of the function:

    >>> histogram([1, 8, 5, 17, 14, 9, 2])
    *
    ********
    *****
    *****************
    **************
    *********
    **
    >>> histogram([1, 8, 5, 17, 2], char="-")
    -
    --------
    -----
    -----------------
    --

    Use the print function to print the histogram row by row. Repeating a string might be useful, for example "*" * 8 is "********".

  2. Define a function sum_of_squares which takes a list of numbers and returns the sum of all squared items (one number). Note that the built-in function sum computes the sum of a list of numbers.

  3. Create a list numbers consisting of the 25 integers from 1 to 25. Based on this list, generate the following five new lists:

    • squares containing the squared numbers
    • evens containing the even numbers
    • odds containing the odd numbers
    • roots containing the square roots of the numbers
    • logs containing the natural logarithms of the numbers

    For the last two lists, use the functions sqrt and log from the math module (first, import math and then use the functions as math.sqrt and math.log, respectively).

  4. Find out what is wrong with the following code:

    x = [1, 2, 3, 4]
    x = x.append(5)

https://creativecommons.org/licenses/by-nc-sa/4.0/ This document is licensed under the CC BY-NC-SA 4.0 by Clemens Brunner.