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: For Loops in Python (Definite Iteration)
Python’s for
loop allows you to iterate over the items in a collection, such as lists, tuples, strings, and dictionaries. The for
loop syntax declares a loop variable that takes each item from the collection in each iteration. This loop is ideal for repeatedly executing a block of code on each item in the collection. You can also tweak for
loops further with features like break
, continue
, and else
.
By the end of this tutorial, you’ll understand that:
- Python’s
for
loop iterates over items in a data collection, allowing you to execute code for each item. - To iterate from
0
to10
, you use thefor index in range(11):
construct. - To repeat code a number of times without processing the data of an iterable, use the
for _ in range(times):
construct. - To do index-based iteration, you can use
for index, value in enumerate(iterable):
to access both index and item.
In this tutorial, you’ll gain practical knowledge of using for
loops to traverse various collections and learn Pythonic looping techniques. Additionally, you’ll learn how to handle exceptions and how to use asynchronous iterations to make your Python code more robust and efficient.
Get Your Code: Click here to download the free sample code that shows you how to use for loops in Python.
Take the Quiz: Test your knowledge with our interactive “The Python for Loop” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
The Python for LoopIn this quiz, you'll test your understanding of Python's for loop and the concepts of definite iteration, iterables, and iterators. With this knowledge, you'll be able to perform repetitive tasks in Python more efficiently.
Getting Started With the Python for
Loop
In programming, loops are control flow statements that allow you to repeat a given set of operations a number of times. In practice, you’ll find two main types of loops:
for
loops are mostly used to iterate a known number of times, which is common when you’re processing data collections with a specific number of data items.while
loops are commonly used to iterate an unknown number of times, which is useful when the number of iterations depends on a given condition.
Python has both of these loops and in this tutorial, you’ll learn about for
loops. In Python, you’ll generally use for
loops when you need to iterate over the items in a data collection. This type of loop lets you traverse different data collections and run a specific group of statements on or with each item in the input collection.
In Python, for
loops are compound statements with a header and a code block that runs a predefined number of times. The basic syntax of a for
loop is shown below:
for variable in iterable:
<body>
In this syntax, variable
is the loop variable. In each iteration, this variable takes the value of the current item in iterable
, which represents the data collection you need to iterate over. The loop body can consist of one or more statements that must be indented properly.
Here’s a more detailed breakdown of this syntax:
for
is the keyword that initiates the loop header.variable
is a variable that holds the current item in the input iterable.in
is a keyword that connects the loop variable with the iterable.iterable
is a data collection that can be iterated over.<body>
consists of one or more statements to execute in each iteration.
Here’s a quick example of how you can use a for
loop to iterate over a list:
>>> colors = ["red", "green", "blue", "yellow"]
>>> for color in colors:
... print(color)
...
red
green
blue
yellow
In this example, color
is the loop variable, while the colors
list is the target collection. Each time through the loop, color
takes on a successive item from colors
. In this loop, the body consists of a call to print()
that displays the value on the screen. This loop runs once for each item in the target iterable. The way the code above is written is the Pythonic way to write it.
However, what’s an iterable anyway? In Python, an iterable is an object—often a data collection—that can be iterated over. Common examples of iterables in Python include lists, tuples, strings, dictionaries, and sets, which are all built-in data types. You can also have custom classes that support iteration.
Note: Python has both iterables and iterators. Iterables support the iterable protocol consisting of the .__iter__()
special method. Similarly, iterators support the iterator protocol that’s based on the .__iter__()
and .__next__()
special methods.
Both iterables and iterators can be iterated over. All iterators are iterables, but not all iterables are iterators. Python iterators play a fundamental role in for
loops because they drive the iteration process.
A deeper discussion on iterables and iterators is beyond the scope of this tutorial. However, to learn more about them, check out the Iterators and Iterables in Python: Run Efficient Iterations tutorial.
You can also have a loop with multiple loop variables:
>>> points = [(1, 4), (3, 6), (7, 3)]
>>> for x, y in points:
... print(f"{x = } and {y = }")
...
x = 1 and y = 4
x = 3 and y = 6
x = 7 and y = 3
In this loop, you have two loop variables, x
and y
. Note that to use this syntax, you just need to provide a tuple of loop variables. Also, you can have as many loop variables as you need as long as you have the correct number of items to unpack into them. You’ll also find this pattern useful when iterating over dictionary items or when you need to do parallel iteration.
Sometimes, the input iterable may be empty. In that case, the loop will run its header once but won’t execute its body:
>>> for item in []:
... print(item)
...
In this example, the target iterable is an empty list. The loop checks whether the iterable has items. If that’s the case, then the loop runs once for each item. If the iterable has no items, then the loop body doesn’t run, and the program’s execution flow jumps onto the statement after the loop.
Now that you know the basic syntax of for
loops, it’s time to dive into some practical examples. In the following section, you’ll learn how to use for
loops with the most common built-in data collections in Python.
Traversing Built-in Collections in Python
When writing Python code, you’ll often need to iterate over built-in data types such as lists, tuples, strings, numeric ranges, dictionaries, and sets. All of them support iteration, and you can feed them into a for
loop. In the next sections, you’ll learn how to tackle this requirement in a Pythonic way.
Sequences: Lists, Tuples, Strings, and Ranges
When it comes to iterating over sequence data types like lists, tuples, strings, and ranges, the iteration happens in the same order that the items appear in the sequence. Consider the following example where you iterate over the numbers in a list:
>>> numbers = [1, 2, 3, 4]
>>> for number in numbers:
... print(number)
...
1
2
3
4
In this example, the iteration goes through the list in the definition order, starting with 1
and ending with 4
. Note that to iterate over a sequence in Python, you don’t need to be aware of the index of each item as in other languages where loops often rely on indices.
Often, you use plural nouns to name lists. This naming practice allows you to use singular nouns as the loop variable, making your code descriptive and readable.
Note: To learn more about using lists, check out Python’s list
Data Type: A Deep Dive With Examples.
You’ll note the same behavior with other built-in sequences:
>>> person = ("Jane", 25, "Python Dev", "Canada")
>>> for field in person:
... print(field)
...
Jane
25
Python Dev
Canada
>>> text = "abcde"
>>> for character in text:
... print(character)
...
a
b
c
d
e
>>> for index in range(5):
... print(index)
...
0
1
2
3
4
In these examples, you iterate over a tuple, string, and numeric range. Again, the loop traverses the sequence in the order of definition.
Note: For more information about tuples, strings, and ranges, you can check out the following tutorials:
Tuples are often used to represent rows of data. In the example above, the person
tuple holds data about a person. You can iterate over each field using a readable loop.
When it comes to iterating over string objects, the for
loop lets you process the string on a character-by-character basis. Finally, iterating over a numeric range is sometimes a requirement, especially when you need to iterate a given number of times and need control over the consecutive index.
Collections: Dictionaries and Sets
When traversing dictionaries with a for
loop, you’ll find that you can iterate over the keys, values, and items of the dictionary at hand.
Note: To learn more about dictionary iteration, check out the How to Iterate Through a Dictionary in Python tutorial.
You’ll have two different ways to iterate over the keys of a dictionary. You can either use:
- The dictionary directly
- The
.keys()
method
The following examples show how to use these two approaches:
>>> students = {
... "Alice": 89.5,
... "Bob": 76.0,
... "Charlie": 92.3,
... "Diana": 84.7,
... "Ethan": 88.9,
... }
>>> for student in students:
... print(student)
...
Alice
Bob
Charlie
Diana
Ethan
>>> for student in students.keys():
... print(student)
...
Alice
Bob
Charlie
Diana
Ethan
In these examples, you first iterate over the keys of a dictionary using the dictionary directly in the loop header. In the second loop, you use the .keys()
method to iterate over the keys. While both approaches are equivalent, the first one is more commonly used, whereas the second might be more readable and explicit.
In both loops, you can access the dictionary values using the keys:
>>> for student in students:
... print(student, "->", students[student])
...
Alice -> 89.5
Bob -> 76.0
Charlie -> 92.3
Diana -> 84.7
Ethan -> 88.9
To access the values in this type of iteration, you can use the original dictionary and a key lookup operation, as shown in the highlighted line.
You can use the .values()
method to feed the for
loop when you need to iterate over the values of a dictionary:
>>> teams = {
... "Colorado": "Rockies",
... "Chicago": "White Sox",
... "Boston": "Red Sox",
... "Minnesota": "Twins",
... "Milwaukee": "Brewers",
... "Seattle": "Mariners",
... }
>>> for team in teams.values():
... print(team)
...
Rockies
White Sox
Red Sox
Twins
Brewers
Mariners
The .values()
method lets you traverse the values in the target dictionary. In this example, you iterate over team names one by one. Note that when you use the .values()
method, you can’t access the dictionary keys.
Finally, iterating over both keys and values in a Python dictionary is a common requirement. In this case, the recommended and most Pythonic approach is to use the .items()
method in a for
loop like the following:
>>> for place, team in teams.items():
... print(place, "->", team)
...
Colorado -> Rockies
Chicago -> White Sox
Boston -> Red Sox
Minnesota -> Twins
Milwaukee -> Brewers
Seattle -> Mariners
When iterating over keys and values this way, you typically use a tuple of loop variables. The first variable will get the key, while the second will get the associated value. In this example, you have the place
and team
variables, which make the code clear and readable.
When it comes to iterating over sets, you only have to keep in mind that sets are unordered data types. This means that looping in order isn’t guaranteed:
>>> tools = {"Django", "Flask", "pandas", "NumPy"}
>>> for tool in tools:
... print(tool)
...
NumPy
Flask
pandas
Django
As you can see, the loop goes through the elements of your set in a different order than they were inserted. So, you can’t rely on the order of the elements when traversing sets in Python.
Using Advanced for
Loop Syntax
The Python for
loop has some advanced features that make it flexible and powerful. These features can be helpful when you need to fine-tune the loop to meet specific execution flows. These features include the break
and continue
statements and the else
clause, which you’ll learn about in the following sections.
You’ll also learn that for
loops can be nested inside one another. This feature can be pretty useful in situations where you need to iterate over nested data structures like lists of lists.
The break
Statement
The break
statement immediately exits the loop and jumps to the first statement after the loop. For example, say that you want to write a loop to determine whether a number is in a list. To avoid unnecessary work, the loop should terminate once it finds the target value. You can do this with the break
statement:
>>> numbers = [1, 3, 5, 7, 9]
>>> target = 5
>>> for number in numbers:
... print(f"Processing {number}...")
... if number == target:
... print(f"Target found {target}!")
... break
...
Processing 1...
Processing 3...
Processing 5...
Target found 5!
In this example, the break
statement jumps out of the loop as soon as the target number is found. The remaining values, 7
and 9
, aren’t processed. You can think of the break
statement as a way to short-circuit the loop execution once you’ve gotten the desired result.
It’s important to note that it makes little sense to have break
statements outside conditionals. Suppose you include a break
statement directly in the loop body without wrapping it in a conditional. In that case, the loop will terminate in the first iteration, potentially without running the entire loop body.
The continue
Statement
The continue
statement terminates the current iteration and proceeds to the next one. For example, if you have a list of numbers and only want to process the even ones, you can use a continue
statement to skip the odd numbers:
>>> numbers = [1, 2, 3, 4, 5, 6]
>>> for number in numbers:
... print(f"{number = }")
... if number % 2 != 0:
... continue
... print(f"{number} is even!")
...
number = 1
number = 2
2 is even!
number = 3
number = 4
4 is even!
number = 5
number = 6
6 is even!
In this example, the code that processes the numbers is only reached if the number is even. Otherwise, the continue
statement skips that code and jumps right into the next iteration.
Again, it doesn’t make much sense to have a continue
statement without wrapping it in a conditional. If you do so, the code after the statement will be unreachable and never run.
The else
Clause
In Python, for
loops can have an else
clause at the end. The else
clause will only run if the loop terminates because of the exhaustion of the input iterable. This feature is useful when you have a break
statement that can terminate the loop in certain situations. If the loop doesn’t break, then you can run additional code in the else
clause.
To illustrate, say that you want to continue improving the loop that determines whether a number is in a list. You’d like to explicitly inform the user if the number isn’t in the list. You can do this with the else
clause:
>>> numbers = [1, 3, 5, 7, 9]
>>> target = 42
>>> for number in numbers:
... print(f"Processing {number}...")
... if number == target:
... print(f"Target found {target}!")
... break
... else:
... print(f"Target not found {target}")
...
Processing 1...
Processing 3...
Processing 5...
Processing 7...
Processing 9...
Target not found 42
The else
clause won’t run if the loop breaks out with the break
statement. It only runs if the loop terminates normally, allowing you to inform the user that the target number wasn’t found.
It doesn’t make sense to have an else
clause in a loop that doesn’t have a break
statement. In that case, placing the else
block’s content after the loop—without indentation—will work the same and be cleaner.
Nested for
Loops
You can also have nested for
loops. In the example below, you create a multiplication table that shows the products of all combinations of integers up to ten using nested loops. The outer loop iterates over the numbers between 1
and 10
, and the inner loop calculates and prints the products:
>>> for number in range(1, 11):
... for product in range(number, number * 11, number):
... print(f"{product:>4d}", end="")
... print()
...
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
In this example, you use two nested loops. Together, they create a two-dimensional multiplication table. First, you loop over the numbers from one up to and including ten. These represent the rows in the table, and you can see those numbers at the beginning of each row.
In the inner loop, you calculate the products for the current number
by iterating from the number
itself up to its tenth multiple. Then, you format each product using the :>4d
format specifier. This ensures the table is nicely aligned. By setting end
to an empty string, you skip the newline until the products on the current row are printed. After printing all products for a row, you use print()
without arguments to move to the next row.
Exploring Pythonic Looping Techniques
When people switch from other programming languages to Python, they often write for
loops like they did in their previous language. This practice makes Python code look odd and hard to read.
In the following sections, you’ll explore some looping techniques, practices, and tips that are considered Pythonic. These techniques can make your Python code look clearer, more elegant, and more efficient.
Iterating With Indices: The Pythonic Way
Sometimes, you need to use the indices of items when you iterate over a sequence with a Python for
loop. Up to this point, you’ve seen examples where you can access the items but don’t know their corresponding indices.
To get both the item and its index, you can end up writing a loop like the one shown in the following example:
>>> fruits = ["orange", "apple", "mango", "lemon"]
>>> for index in range(len(fruits)):
... fruit = fruits[index]
... print(index, fruit)
...
0 orange
1 apple
2 mango
3 lemon
This loop gets the job done, but it’s not as clean or readable as you’d expect from Python code. Fortunately, there’s a better way—the built-in enumerate()
function:
>>> for index, fruit in enumerate(fruits):
... print(index, fruit)
...
0 orange
1 apple
2 mango
3 lemon
The enumerate()
function takes an iterable as an argument and generates tuples of the form (index, item)
. Note that the loop reads almost like plain English, which makes your code way more Pythonic than the previous version using range()
.
Note: To learn more about working with enumerate()
, check out the Python enumerate()
: Simplify Loops That Need Counters tutorial.
The enumerate()
function also takes an optional argument called start
that lets you tweak the initial value. This feature is useful when you need to create counts. Consider the following example that mimics an option menu for a command-line application:
>>> def display_menu(options):
... print("Main Menu:")
... for position, option in enumerate(options, start=1):
... print(f"{position}. {option}")
...
>>> display_menu(["Open", "Save", "Settings", "Quit"])
Main Menu:
1. Open
2. Save
3. Settings
4. Quit
In this example, instead of using enumerate()
to produce zero-based indices, you start the count at 1
. From the end user’s perspective, starting the menu at 1
is the natural way to go.
Looping Over Several Iterables in Parallel
Looping through two or more iterables in parallel may be another common task you encounter in Python programming. To do this, you can use the built-in zip()
function, which takes two or more iterables and yields tuples that combine items from each iterable.
Note: To learn more about zip()
, check out the Using the Python zip() Function for Parallel Iteration tutorial.
Consider the following toy example:
>>> numbers = [1, 2, 3]
>>> letters = ["a", "b", "c"]
>>> for number, letter in zip(numbers, letters):
... print(number, "->", letter)
...
1 -> a
2 -> b
3 -> c
In this example, you use zip(numbers, letters)
to create an iterator that produces tuples of the form (number, letter)
. In this case, the number
values are taken from numbers
, and the letter
values are taken from letters
.
Iterating Over Multiple Iterables Sequentially
There may be times when you need to iterate over multiple iterables sequentially in a single loop. In such cases, you can use the chain()
function from Python’s itertools
module.
Note: To learn more about the itertools
module and the tools it provides, check out the Python itertools
By Example tutorial.
For example, say that you have several lists of numbers and want to calculate the square of each number in all lists. You can use chain()
as follows:
>>> from itertools import chain
>>> first = [7, 6, 1]
>>> second = [4, 1]
>>> third = [8, 0, 6]
>>> for value in chain(first, second, third):
... print(value**2)
...
49
36
1
16
1
64
0
36
This loops over all three lists in sequence and prints the square of each value. You can also use chain()
to work through a list of lists. Say that you, again, need to process each value in a sequence and calculate its square:
>>> matrix = [
... [9, 3, 8],
... [4, 5, 2],
... [6, 4, 3],
... ]
>>> for value in chain(*matrix):
... print(value**2)
...
81
9
64
16
25
4
36
16
9
In this example, you use chain()
to iterate over the rows of the matrix. To feed the rows into chain()
, you use the unpacking operator (*
). Inside the loop, you calculate and print the square of each value.
Using chain()
, like in this example, essentially flattens the matrix into a single iterable, helping you avoid a nested loop, which can be difficult to read and understand in some contexts.
Repeating Actions a Predefined Number of Times
Iteration is all about repeating some fragment of code multiple times. As you’ve learned so far, for
loops are designed to repeat a given set of actions on the items of an iterable. However, you can also use this type of loop to quickly iterate a specific number of times. This is useful when you need to repeat a bunch of statements, but they don’t operate on the items of an iterable.
Here’s a fun example about Penny and Sheldon to illustrate this:
>>> for _ in range(3):
... print("Knock, knock, knock")
... print("Penny!")
...
Knock, knock, knock
Penny!
Knock, knock, knock
Penny!
Knock, knock, knock
Penny!
This loop runs three times and repeats a series of statements that don’t operate on any iterable. Note that the loop variable is a single underscore character in this example. This variable name communicates that you don’t need to use the loop variable inside the loop. It’s a throwaway variable.
With this looping construct that takes advantage of range()
, you have full control over the number of times your code runs.
Iterating Over Reversed and Sorted Iterables
Iterating over the items of an iterable in reverse or sorted order is also a common requirement in programming. To achieve this, you can combine a for
loop with the built-in reversed()
or sorted()
function, respectively.
Note: To learn more about reversed()
and sorted()
, check out the following tutorials:
For example, say that you’re working on a text editor and want to implement a basic Undo option. You can implement it with the reversed()
function and a loop like the following:
>>> actions = ["Type text", "Select text", "Cut text", "Paste text"]
>>> for action in reversed(actions):
... print(f"Undo: {action}")
...
Undo: Paste text
Undo: Cut text
Undo: Select text
Undo: Type text
In this example, you have a list of hypothetical user actions in a text editor. The actions are stored in a list from oldest to newest. To implement the Undo operation, you need to reverse the actions, which you do with reversed()
.
To iterate in sorted order, say that you have a dictionary that maps student names to their corresponding average grades. You need to create a quick report and want to sort the data from highest to lowest grades. For this, you can do something like the following:
>>> students = {
... "Alice": 89.5,
... "Bob": 76.0,
... "Charlie": 92.3,
... "Diana": 84.7,
... "Ethan": 88.9,
... "Fiona": 95.6,
... "George": 73.4,
... "Hannah": 81.2,
... }
>>> sorted_students = sorted(
... students.items(), key=lambda item: item[1], reverse=True
... )
>>> for name, grade in sorted_students:
... print(f"{name}'s average grade: {grade:->{20-len(name)}.1f}")
...
Fiona's average grade: -----------95.6
Charlie's average grade: ---------92.3
Alice's average grade: -----------89.5
Ethan's average grade: -----------88.9
Diana's average grade: -----------84.7
Hannah's average grade: ----------81.2
Bob's average grade: -------------76.0
George's average grade: ----------73.4
The sorted()
function returns a list of sorted values. In this example, you sort the dictionary by its values in ascending order. To do this, you use a lambda
function that takes a two-value tuple as an argument and returns the second item, which has an index of 1
. You also set the reverse
argument to True
so that the function stores the data in reverse order. In this case, this means that the grades are ordered in descending order.
The for
loop iterates over the sorted data and generates a nicely formatted report using an f-string with a custom format specifier.
Understanding Common Pitfalls in for
Loops
When working with for
loops in your Python code, you may encounter some issues related to incorrect ways to use this tool. Some of the most common bad practices and incorrect assumptions include:
- Modifying the loop collection or iterable during iteration
- Changing the loop variable to affect the underlying collection
- Ignoring possible exceptions that may occur
In the following sections, you’ll explore these pitfalls and how to avoid them in your for
loops.
Modifying the Loop Collection
Python has mutable collections, such as lists and dictionaries, that you can modify in place. You may want to change a list while looping over it. In this situation, you need to distinguish between safe and unsafe changes.
For example, say that you have a list of names and want to convert them into uppercase. You may think of doing something like the following:
>>> names = ["Alice", "Bob", "John", "Jane"]
>>> for index, name in enumerate(names):
... names[index] = name.upper()
...
>>> names
['ALICE', 'BOB', 'JOHN', 'JANE']
In this example, you only change the existing items in the list without adding or removing any. This operation is safe. However, modifying a mutable iterable like a list while iterating over it always raises a warning.
Issues may appear when you add or remove items from a list while iterating over it. To understand why this is best avoided, say that you want to remove all the even numbers from a list. You might write the following code:
>>> numbers = [2, 4, 6, 8]
>>> for number in numbers:
... if number % 2 == 0:
... numbers.remove(number)
...
>>> numbers
[4, 8]
After running the loop, some even numbers remain, even though you expected the list to be empty.
On the first iteration, 2
is removed, and the list shifts left, becoming [4, 6, 8]
. The loop then jumps to the next item, skipping 4
and processing 6
instead. Then 6
is removed, and the list shifts again, becoming [4, 8]
. The iteration ends before reaching 8
.
When you need to resize a list during iteration like in the example above, it’s recommended to create a copy of the list:
>>> numbers = [2, 4, 6, 8]
>>> for number in numbers[:]:
... if number % 2 == 0:
... numbers.remove(number)
...
>>> numbers
[]
The slicing operator ([:]
) with no indices creates a copy of the original list for iteration purposes. The loop traverses the copy while removing values from the original list.
In some cases, creating a copy of the input list isn’t enough. Say that on top of removing even numbers, you want to calculate the square of odd numbers. You might modify the previous loop as shown in the following code:
>>> numbers = [2, 1, 4, 6, 5, 8]
>>> for index, number in enumerate(numbers[:]):
... if number % 2 == 0:
... numbers.remove(number)
... else:
... numbers[index] = number**2
...
Traceback (most recent call last):
...
ValueError: list.remove(x): x not in list
This time, you use enumerate()
to generate index-item pairs. Then, you think of using the index to update the value of a given item. However, the code fails with a ValueError
exception. Creating a copy of the input list isn’t enough in this case. You’d have to make a separate list to store the result:
>>> numbers = [2, 1, 4, 6, 5, 8]
>>> processed_numbers = []
>>> for number in numbers:
... if number % 2 != 0:
... processed_numbers.append(number**2)
...
>>> processed_numbers
[1, 25]
In this new loop implementation, you’re using a new list to store the result. Because of this, you don’t have to remove items anymore. You add the square values to the end of the new list using the .append()
method.
Python doesn’t allow you to add or remove items from a dictionary while you’re iterating through it:
>>> values = {"one": 1, "two": 2, "three": 3, "four": 4}
>>> for value in values:
... values["five"] = 5 # Attempt to add an item
...
Traceback (most recent call last):
...
RuntimeError: dictionary changed size during iteration
>>> for value in values:
... del values[value] # Attempt to remove an item
...
Traceback (most recent call last):
...
RuntimeError: dictionary changed size during iteration
If you try to expand or shrink a dictionary during iteration, you get a RuntimeError
exception. Again, you can work around this by creating a copy of the dictionary using the .copy()
method or by building a new dictionary with the resulting data.
Changing the Loop Variable
Changing the loop variable in the loop body doesn’t have an effect on the original data:
>>> names = ["Alice", "Bob", "John", "Jane"]
>>> for name in names:
... name = name.upper()
... print(name)
...
ALICE
BOB
JOHN
JANME
>>> names
['Alice', 'Bob', 'John', 'Jane']
In this example, the highlighted line changes the loop variable, name
. This change doesn’t affect the original data in your list of names. The loop variable is just a temporary reference to the current item in the iterable, and reassigning it doesn’t affect the loop iterable.
Ignoring Possible Exceptions
If an exception occurs in a loop body and isn’t handled, the loop will terminate prematurely, skipping subsequent iterations. This result can generate unexpected issues, especially when you rely on the loop to process data, perform logging, or run cleanup actions in each iteration.
As an example, say that you want to process some text files in a loop:
>>> files = ["file1.txt", "file2.txt", "file3.txt"]
>>> for file in files:
... with open(file, "r") as f:
... print(f"Contents of {file}:")
... print(f.read())
...
Traceback (most recent call last):
...
FileNotFoundError: [Errno 2] No such file or directory: 'file1.txt'
In this example, none of the files exist in your working directory. The loop tries to process the first file and fails with a FileNotFoundError
exception. Because the exception wasn’t handled properly, the loop terminates in the first iteration, skipping the rest of the files in the list.
To avoid this behavior, you need to catch and handle the exception:
>>> files = ["file1.txt", "file2.txt", "file3.txt"]
>>> for file in files:
... try:
... with open(file, "r") as f:
... print(f"Contents of {file}:")
... print(f.read())
... except FileNotFoundError:
... print(f"Error: {file} not found. Skipping.")
...
Error: file1.txt not found. Skipping.
Error: file2.txt not found. Skipping.
Error: file3.txt not found. Skipping.
In this new implementation, the loop catches any FileNotFoundError
exception and prints an error message to the screen. The loop runs entirely without abrupt interruptions.
Using for
Loops vs Comprehensions
When you use for
loops to transform data and build new collections, it may be possible to replace the loop with a comprehension. For example, consider the loop below:
>>> cubes = []
>>> for number in range(10):
... cubes.append(number**3)
...
>>> cubes
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
In this example, you first define an empty list called cubes
. Then, you use a loop to iterate over a range of integer numbers and populate the list with cube values.
Note: To learn more about comprehensions in Python, check out the following tutorials:
You can quickly replace the above loop with a list comprehension like the following:
>>> cubes = [number**3 for number in range(10)]
>>> cubes
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
The comprehension iterates over the range of numbers and builds the list of cubes in a single line of code.
Using async for
Loops for Asynchronous Iteration
The async for
statement allows you to create loops that iterate over asynchronous iterables. This type of loop works pretty much the same as regular for
loops, but the loop collection must be an asynchronous iterator or iterable.
Note: To learn more about asynchronous iteration, check out the Asynchronous Iterators and Iterables in Python tutorial.
The example below shows an AsyncRange
class that generates ranges of integer values asynchronously. You can use this iterable in an async for
loop:
async_range.py
import asyncio
class AsyncRange:
def __init__(self, start, end):
self.data = range(start, end)
async def __aiter__(self):
for index in self.data:
await asyncio.sleep(0.5)
yield index
async def main():
async for index in AsyncRange(0, 5):
print(index)
asyncio.run(main())
In this code, the loop in the highlighted line iterates over integer indices from 0
to 5
in an asynchronous manner.
When you run this script, you get the following output:
$ python async_range.py
0
1
2
3
4
In this output, each number is obtained after waiting half a second, which is consistent with the asynchronous iteration.
Conclusion
You’ve learned how to use Python for
loops to iterate over various data collections, including lists, tuples, strings, dictionaries, and sets. You’ve explored advanced loop features like the break
and continue
statements, the else
clause, and nested loops. Additionally, you learned about Pythonic looping techniques, common pitfalls, and the use of async for
loops for asynchronous iteration.
Understanding for
loops is essential for Python developers, as they offer an efficient way to manage repetitive tasks and process data. Mastering for
loops helps you write code that is more Pythonic, performant, and easier to maintain.
In this tutorial, you’ve learned how to:
- Iterate over different Python collections using
for
loops - Use advanced features like
break
,continue
, andelse
in loops - Apply Pythonic techniques for cleaner and more efficient loops
- Work around common pitfalls when working with loops
- Use
async for
loops for asynchronous data processing
With these skills, you can now write more efficient and readable Python code that leverages the power of for
loops to handle a wide range of data processing tasks.
Get Your Code: Click here to download the free sample code that shows you how to use for loops in Python.
Frequently Asked Questions
Now that you have some experience with Python for
loops, you can use the questions and answers below to check your understanding and recap what you’ve learned.
These FAQs are related to the most important concepts you’ve covered in this tutorial. Click the Show/Hide toggle beside each question to reveal the answer.
You use a for
loop to iterate over a list by specifying the loop variable and the list. For example, for item in a_list:
allows you to process each item in a_list
.
An iterable is an object capable of returning its members one at a time, while an iterator is an object that represents a stream of data, returning the next item with a .__next__()
special method.
You can iterate over both keys and values in a dictionary using the .items()
method in a for
loop, like for key, value in a_dict.items():
.
If you modify a list while iterating over it, you may encounter unexpected behavior, such as skipping elements or runtime errors. It’s recommended to iterate over a copy of the list instead. In some cases, it’s necessary to create a new list to keep the result.
To handle exceptions in a for
loop, wrap the code that might raise an exception in a try
block. Then use an except
block to catch the exception, manage the error, and continue the iteration.
Take the Quiz: Test your knowledge with our interactive “The Python for Loop” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
The Python for LoopIn this quiz, you'll test your understanding of Python's for loop and the concepts of definite iteration, iterables, and iterators. With this knowledge, you'll be able to perform repetitive tasks in Python more efficiently.
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: For Loops in Python (Definite Iteration)