# How to use for loops in Python: a practical guide

The for loop in Python is used to **repeatedly execute a block of code**. For loops are a fundamental part of most programming languages. Keep reading to find out how the for loop works in Python and how to use it.

## What is the for loop in Python?

The for loop is one of the most well-known programming constructs. Let’s look at it using a concrete example from everyday life. Say that a teacher wants to calculate the average height of her students. First **she’ll ask each student in turn what their height is and add each student’s height to the running total**. Once she’s done that for every student, she’ll divide the total by the number of students there are to get the average height of her students. We can build a basic algorithm based on the teacher’s actions:

1. Ask for the height of each student and add it to the running total.
2. Divide the total by the total number of students.

The first step will be executed once for each student and **doesn’t require knowing the number of students in the class**. The second step is only executed once, no matter how many students are in the class. We’ll need a loop for the first step.

Here’s how the whole algorithm would look in Python, including a for loop:

```none
student_heights = [60, 65, 56, 71, 58, 63, 67]
height_sum = 0
for height in student_heights:
    height_sum = height_sum + height
average_height = height_sum // len(student_heights)
print(average_height)
```

So, the Python for loop repeatedly executes a block of code. This is also referred to as 'iteration'. Loops make it possible to repeat a process for several elements of a sequence. For loops are used in Python when the size of a sequence can be determined at program runtime. Otherwise, a Python while loop is usually used.

---

### Tip

Learn how to program in Python with our [Python tutorial](https://www.ionos.co.uk/digitalguide/websites/web-development/python-tutorial/ "Python tutorial")!

---

## What’s the difference between the for loop in Python and other languages?

Many other programming languages implement for loops in some way. They’re **fundamental** to languages like C, Java, JavaScript and PHP. Purely functional programming languages like Haskell and Lisp usually don’t use explicit for loops. They use recursive functions instead of iterations.

Every loop involves repeatedly executing a block of code. However, **the for loop in Python works fundamentally differently** than for loops in other languages. Most programming languages use a loop variable, which is incremented or decremented with each successful iteration of the loop.

<table>
  <thead>
    <tr>
      <th>Operation</th>
      <th>Meaning</th>
      <th>Typical syntax</th>
      <th>Python syntax</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Increment</td>
      <td>Increase the value of an integer variable by a specific, fixed amount</td>
      <td>i++</td>
      <td>index += 1</td>
    </tr>
    <tr>
      <td>Decrement</td>
      <td>Decrease the value of an integer variable by a specific, fixed amount</td>
      <td>i--</td>
      <td>index -= 1</td>
    </tr>
  </tbody>
</table>

To see how this makes a difference, let’s take a look at an example of how for loops work in other languages. We’ll output the numbers 0 to 9 in JavaScript with a for loop. To do this, we’ll define an integer variable called 'number' and increment it if its value is less than 10. The code for this in JavaScript will probably look incomprehensible to beginners:

```none
for ( let number = 0; number < 10; number++ ) {
    console.log(number);
}
```

On the other hand, the code for the same for loop in Python is significantly easier to follow:

```none
for number in range(10):
    print(number)
```

Rather than directly outputting the loop variable, **one element from a collection is usually used for indexing**. Let’s look at another example from JavaScript, in which we output the names from the list 'people'. We’ll use the loop variable 'i' as the running index of the individual elements:

```none
people = ['Jack', 'Jim', 'John']
for (let i = 0; i < people.length; i++) {
    console.log("Here comes " + people[i]);
}
```

Be careful about directly indexing successive elements in a list. If the loop is executed one too many times, you’ll end up with a runtime error, often the infamous 'off-by-one error'. Python does away with this problem. Below we show the same case implemented in Python. We iterate over the list elements without indexing them using a loop variable:

```none
people = ['Jack', 'Jim', 'John']
for person in people:
    print(f"Here comes {person}")
```

The indirect use of loop variables leads to a lot of confusion for people learning about for loops in languages other than Python. The loop variable is at the centre of the code, even though it usually doesn’t play a crucial role ⁠— its only purpose is to index the individual elements. Anyone hoping to use typical for loops will need to understand several other complex topics. For example, in JavaScript:

<table>
  <thead>
    <tr>
      <th>Topic</th>
      <th>In JavaScript for loop</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Assigning variable</td>
      <td>let i = 0</td>
    </tr>
    <tr>
      <td>Boolean expressions</td>
      <td>i &lt; limit</td>
    </tr>
    <tr>
      <td>Increment/decrement operator</td>
      <td>i++ / i--</td>
    </tr>
    <tr>
      <td>Determining size of list</td>
      <td>i &lt; list.length</td>
    </tr>
    <tr>
      <td>Zero-based indexing of elements</td>
      <td>i &lt; list.length is ok; i &lt;= list.length results in off-by-one error</td>
    </tr>
  </tbody>
</table>

The for loop in Python is significantly more user friendly. Despite its use of the same word 'for', it takes a fundamentally different approach. Instead of incrementing a loop variable and indexing successive elements, it iterates directly over the elements in a sequence. The for loop in Python is comparable to the forEach construct found in languages like Ruby and JavaScript.

For example, say we want to output the individual letters of a word. One letter will be made available via the variable 'letter' for each iteration of the loop. It does without a loop variable, meaning that there’s no risk of an off-by-one error. The code is precise and easy to read:

```none
word = "Python"
for letter in word:
    print(letter)
```

## How does the for loop work in Python?

As we’ve seen, the Python for loop elegantly solves the problem of **iterating over the elements in a list**. The key is leaving out the loop variable. But how does that work? To understand how the Python for loop works, you’ll first need to know a bit about iterables and iterators.

### What are iterables, iterators and generators?

In Python, the for loop **operates on objects known as 'iterables'**. This includes strings, lists, tuples and other collections of data. In the words of the official Python documentation:

---

### Quote

&gt; “\[An iterable is\] an object capable of returning its members one at a time” — Source: https://docs.python.org/3/glossary.html#term-iterable

---

An **iterable object** has two properties:

1. It brings together multiple elements as a collection.
2. It provides access to the elements via an iterator.

Bringing these two points together, we can say that iterables are collections whose contents can be iterated over. Specifically, iterables have a method '\_\_iter\_\_()' that generates an iterator. An iterator is an **object that can return the next element of an iterable on command**. An iterator also remembers the position of the last returned object form the collection.

<table>
  <thead>
    <tr>
      <th>Function</th>
      <th>Explanation</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>iter(collection)</td>
      <td>Calls the \_\_iter\_\_() method of the collection</td>
      <td>it = iter("Python")</td>
    </tr>
    <tr>
      <td>next(iter)</td>
      <td>Calls the \_\_next\_\_() method of the iterator</td>
      <td>next(it)</td>
    </tr>
    <tr>
      <td>collection\[index\]</td>
      <td>Calls the \_\_getitem\_\_(index) method of the collection</td>
      <td>'Python'\[1\]</td>
    </tr>
  </tbody>
</table>

When the method \_\_next\_\_() is called, the iterator returns the next element. **The iterator is exhausted when all of the elements in the collection have been returned**. Calling \_\_next\_\_() again will raise the 'StopIteration' exception.

Let’s take a look at how this all **works in practice using an example**. We’ll create a range() object that represents the consecutive numbers from 21 to 23. Then we’ll create an iterator with the iter() function and return successive elements with the next() function. The exception will be raised on the last call, since the iterator is exhausted:

```none
numbers = range(21, 24)
number = iter(numbers)
next(number)
# returns `21`
next(number)
# returns `22`
next(number)
# returns `23`
next(number)
# raises `StopIteration` exception
```

The iterator provides access to the individual elements in a collection. In addition, there’s the related concept of the generator. Unlike an iterator, a **generator creates the individual elements at the time of access**. This use of 'lazy execution' saves memory.

Generators in Python are functions that contain at least one yield statement. **Similar to the return statement, the yield statement returns an object** and ends the call. However, unlike the return statement, the yield statement will pick up where it left off on successive calls.

Let’s look at an example. We’ll write our own implementation of the range() function using a yield statement in the while loop to generate continuous numbers:

```none
def my_range(start, stop):
    if stop < start:
        return None
    current = start
    while current < stop:
        yield current
        current += 1
# test
assert list(my_range(7, 9)) == list(range(7, 9))
```

### Skipping iterations and terminating a for loop in Python

Sometimes it’s necessary to skip individual iterations of a loop. Like other languages, Python has a continue statement for **jumping to the next iteration**.

The continue statement **can be used much like early return**. For example, we might want to skip past an iteration after it becomes clear that the data set doesn’t have the characteristic we’re looking for:

```none
def process_data(data):
    for data_set in data:
        data_set.validate()
        # early continue after cheap check fails
        if not data_set.quality_ok():
            continue
        # expensive operation guarded by early continue
        data_set.process()
```

Or, as another example, we output a text and **skip every other letter**:

```none
text = 'Skipping every second letter'
for index, letter in enumerate(text):
    if index % 2 != 0 and letter != ' ':
        continue
    print(letter)
```

In addition to the continue statement, there’s also the break statement, which **terminates the loop**. The role of break in loops is similar to that of return in functions.

The break statement is often used in search algorithms. If the element being searched for was found, it’s not necessary to execute further iterations. In the example below, we check the list for the presence of a single true value and terminate it once we’ve found one:

```none
bool_list = [False, False, True, False]
for index, boolean in enumerate(bool_list):
    if boolean:
        print(f"Value at position {index + 1} is True")
        print(f"Aborting inspection of remaining {len(bool_list) - index - 1} item(s)")
        break
```

For loops in Python can contain **optional 'else' bodies**. The body of else will be executed when the loop is terminated, without the break statement having been executed:

```none
def find_element(target, collection):
    for element in collection:
        if element == target:
            print("Found what you're looking for")
            break
    else:
        print("Didn't find what you were looking for")
# test
find_element('a', 'Python')
find_element('o', 'Python')
```

For loops in Python often appear as parts of functions. In this case, you would **use a return statement rather than a break statement**. Take a look at this alternate version of our search algorithm without break and else:

```none
def find_element(target, collection):
    for element in collection:
        if element == target:
            print("Found what you're looking for")
            # returning breaks us out of the loop
            return element
    # we made it here without returning
    print("Didn't find what you were looking for")
    return None
# test
print(find_element('a', 'Python'))
print(find_element('o', 'Python'))
```

## What are the best practices for for loops in Python?

For loops in Python are primarily used to **iterate over the elements of a sequence or collection**. But there are also more direct methods for many common use cases. Below we’ll look at some best practices and anti-patterns. First, you’ll want to review these key terms:

<table>
  <thead>
    <tr>
      <th>Term</th>
      <th>Explanation</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Collection</td>
      <td>Several elements that have been brought together; a collection is an iterable</td>
      <td>('Walter', 'White'), \[4, 2, 6, 9\], 'Python'</td>
    </tr>
    <tr>
      <td>Iterator</td>
      <td>Interface for iterating over collections</td>
      <td>it = iter('Python')</td>
    </tr>
    <tr>
      <td>Generator</td>
      <td>Function that uses a yield statement rather than a return statement; a generator is an iterable</td>
      <td>range(10)</td>
    </tr>
    <tr>
      <td>Comprehension</td>
      <td>Iterating expression; creates a new collection based on an iterable</td>
      <td>\[num \*\* 2 for num in range(10)\]</td>
    </tr>
  </tbody>
</table>

### Directly iterating over the elements in a collection

One mistake often made by beginners is to use the len() function as a limit to the range() function. This creates a numerical loop variable, indexing the individual elements of the collection.

```none
word = 'Python'
for i in range(len(word)):
    print(word[i])
```

This anti-pattern is **frowned upon**, with good reason. It’s much better to use the Python for loop to iterate directly over the elements in a collection:

```none
word = 'Python'
for letter in word:
    print(letter)
```

### Listing the elements in a collection with enumerate(), including index

Sometimes you **need the index of an element in a collection**. Instead of creating the index as a loop variable, use the [enumerate()](https://www.ionos.co.uk/digitalguide/websites/web-development/python-enumerate/) function. The function will return the tuple (index, element). Make sure that the index starts counting at zero.

```none
names = ["Jim", "Jack", "John"]
for index, name in enumerate(names):
    print(f"{index + 1}. {name}")
```

### Iterating over tuples with the zip() function

Another situation that frequently arises is **simultaneously iterating over elements from two collections of equal length**. The Python approach to this situation uses the zip() function, which takes two collections of the same size and returns 2-tuples:

```none
people = ('Jim', 'Jack', 'John')
ages = (42, 69, 13)
# ascertain both collections are same length
assert len(people) == len(ages)
# iterate over tuples of (person, age)
for person, age in zip(people, ages):
    print(f"{person} is {age} years old")
```

### Generating a numerical loop variable with the range() function

For loops are normally used in Python to iterate over the elements in a collection. They usually aren’t used to increment an integer. The best way to do this is to create a range object using the range() function and iterate over that:

```none
for counter in range(10):
    print(counter)
```

### Using the in operator to test whether a collection contains an element

Finding an element from within a collection is a fundamental tool for any programmer. Normally, you would use a function that iterates over the elements and **checks each element against the element being searched for**. When the element is found, the iteration is terminated.

In Python there’s a special operator for this purpose, the in operator. It checks whether a collection contains the element being searched for and returns the corresponding Boolean value:

```none
'a' in 'Python'
'y' in 'Python'
```

### Creating a list from an iterable using the list() function

Unlike in many other programming languages, you don’t need to use a for loop in Python to **bring the individual letters from a string into a list**. In Python, you can use the list() function to convert an iterable into a list of elements. Let’s take a look at those two different approaches. Using the first approach, we would iterate over the letters in a word and insert them into an empty list:

```none
word = 'Python'
letters = []
for letter in word:
    letters.append(letter)
```

We can save ourselves all these extra steps. Using the second approach, we can create a list right away with the list() function. At the same time, we can check that the two approaches deliver the same result:

```none
assert list(word) == letters
```

Let’s look at another example. We’ll create a list of numbers from zero to nine using a range object as the iterable:

```none
list(range(10))
```

Like lists, sets can also be created using iterables. Below we’ll create a set that contains all the letters in a certain sentence. Then we’ll use the in operator to check that the set doesn’t contain an 'a':

```none
alphabet = set('Python is not hyped')
assert 'a' not in alphabet
```

## Replacing Python for loops with comprehensions

One common use for for loops in Python is modifying the elements of a collection. For example, you might want to **calculate new values based on a collection** or filter certain elements. The steps involved in doing this with a for loop would be as follows:

1. Iterate over the collecting using a for loop.
2. Process each element.
3. If necessary, create a new collection from subsets of the elements.

This is a lot of work for simple modifications. Functional languages show us that it can be easier. Luckily Python has comprehensions, which can **replace for loops in simple cases** and perform better.

Comprehensions **create modified collections based on iterables** using concise and effective syntax. Let’s take a look at the general syntax of a list comprehension. We’ll write the expression in square brackets. In this example, an operation is carried out on the elements of a collection, and each element is copied into a new list:

```none
[ operation(element) for element in collection ]
```

Elements can also be **filtered** using the if statement and a condition:

```none
[ operation(element) for element in collection if condition(element) ]
```

Let’s now take a look at an example of a **for loop in Python that can be replaced by a comprehension**. We start with a list of numbers and want to calculate a list of their squares:

```none
numbers = [2, 3, 5, 9, 17]
```

If we wanted to use a for loop, we would **create an empty list and fill it with the squares as a part of the loop**:

```none
squares = []
for number in numbers:
    squares.append(number ** 2)
```

However, this can be done **much more easily using a comprehension**:

```none
squares_comp = [number ** 2 for number in numbers]
```

We can use the assert statement to check whether the **two approaches deliver the same result**:

```none
assert squares == squares_comp
```

Let’s take a look at another example. Say we want to **extract all the lowercase letters from a string**. First we’ll create a list consisting of both lowercase and uppercase letters:

```none
word = list("PyThoN")
```

If we wanted to use a for loop, we’d iterate over the letters and **test each letter using the islower() function**. Those that pass the test would be added to an empty list:

```none
lowers = []
for letter in word:
    if letter.islower():
        lowers.append(letter)
```

However, there’s no need for this for loop in Python. Instead we’ll use a comprehension, which only copies the lowercase letters from the original list:

```none
lowers_comp = [ letter for letter in word if letter.islower() ]
```

Finally, we’ll again use the assert statement to make sure the two approaches deliver the same result:

```none
assert lowers == lowers_comp
```


This is a markdown version of: [https://www.ionos.co.uk/digitalguide/websites/web-development/python-for-loop/](https://www.ionos.co.uk/digitalguide/websites/web-development/python-for-loop/) for AI/LLM consumption.