Register to get access to free programming courses with interactive exercises

The for loop Python: Lists

Earlier, we looked at while loops. This construction repeats a set of actions. Anything beyond repetition requires additional means of storing the state.

Here, we will take the counter that we change in the loop as an example. When working with collections, we choose which item we're working on within the current iteration. So should we use a variable counter every time?

All programmers want to automate routine work, and language writers are no exception. That's why Python has a different kind of loop for working with collections — the for loop.

It's worth noting that this loop isn't like loops with the same name in other programming languages. This loop is just a supplement to the variable-counter loop termination condition in many languages.

Python has gone further, so in this language, the for loop immediately goes through the elements of the input collection, and you often don't need to think about the index at all.

The syntax

The for loop is simple:

for element in collection:
    print(element)  # This is the body of the cycle

Note that loops don't have an explicit termination condition in the simplest case. The loop stops when the collection runs out of items.

The example above will work for tuples and lists. In this case, we will see all elements. And you can also iterate — traverse a collection. In this case, the loop variable element will contain all characters of the string in turn:

for c in 'Hello!':
    print(c)

# => H
# => e
# => l
# => l
# => o
# => !

But what do we do when we need to get the list of items one by one and change those items? After all, we need the index of each element.

Python has the handy enumerate function for this. This function provides each element with an index and puts them into a tuple together. These tuples are usually unpacked right in the first string of the loop:

items = ['foo', 'bar', 'baz']
for (index, elem) in enumerate(items):
    items[index] = elem + '!'

print(items)  # => ['foo!', 'bar!', 'baz!']

In this loop, we replaced each element with the original value, with the string '!' added at the end. We can write this code in a slightly different way:

items = ['foo', 'bar', 'baz']
for (index, _) in enumerate(items):
    items[index] += '!'

print(items)  # => ['foo!', 'bar!', 'baz!']

This time we use only indexes. Therefore, we have an underscore instead of the loop variable into which we packed the elements.

It isn't some specific variable, just a convention. In Python, you often write insignificant things to the variable _ in this context.

Note the last example did talk about indexes, but we still didn't use the collection length. The enumerate function also knows where to stop: at the end of the original collection.

The break and continue command for loops

Sometimes you don't have to get to the end of the collection. For example, when searching for an element that satisfies a condition. Once we've found the first suitable element, we would do well to save resources and finish the loop.

We do this early exit from the loop using the break command.

Here's a loop to find the first positive number:

items = [-2, 0, -10, 3, 5, -1]
for item in items:
    if item > 0:
        break

print(item)  # => 3

As you may have noticed, the loop variable was available even after the loop ended. However, if the collection is empty, Python will not define the variable — keep this in mind.

This code seems to work as it should. However, if there's no positive number in the list, the item variable will contain only the last item from the list.

So how do we know we haven't found anything? The else is here to help. It is executed in the loop if break doesn't get used. It is perfect for search algorithms. Let's rewrite our example using else:

items = [-2, 0, -10, -1]
for item in items:
    if item > 0:
        break
else:
    item = None

print(item)  # => None

Now suppose we realized during the execution of the loop body that there's no need to execute the rest of the body and that we can proceed immediately to the next iteration.

Use the command continue to go to the next iteration. We read strings containing lines of code, but we don't need to process the code from lines that begin with the # symbol.

It is what the code will look like:

lines_of_code = [
    '# begin of example',
    'echo 123',
    'cd foo',
    '# end']
for line in lines_of_code:
    if line[:1] == '#':
        continue
    # We process the code here
    print(line)

# => echo 123
# => cd foo

Of course, a conventional construction wouldn't hurt. In this case, the code that handles the necessary strings would be nested deeper. And we should try to keep the nesting of code within reasonable limits. Otherwise, the code will very quickly become very difficult to read.

The use of break, continue, else, and while

The else branch and the break and continue commands are also available for the while loop. Here's a comprehensive example that demonstrates all these abilities:

tries_count = 3
while tries_count:
    print('>>> ', end='')
    command = input()
    if not command:
        continue
    if command in ('echo', 'cd', 'help'):
        break
    print('Unknown command!')
    tries_count -= 1
else:
    print('Too many bad tries!')
    command = None

This code asks the user to enter one of the commands, ignores blank input, and limits the number of attempts to enter a command. Think about which part of the loop body is responsible for what.

The for loops and mutable collections

We advise you not to change the list composition while iterating in the `for' loop. If you remove items from the list you're traversing or even add new ones at the end, the result can be unexpected, up to and including an error crashing the program. It is better to fill a new list while traversing the old one.

If you want to change the composition of the original list, then traverse the copy of the list in another loop:

for x in original_list[:]:
    original_list.pop(0)

You can also create a temporary list, clear the original one and add items from the temporary one:

new_list = []
for x in original_list:
    ...
original_list[:] = []  # Removing the old content
original_list.extend(new_list)

Of course, you can combine these two options:

  • First, make a copy
  • Then clear the original
  • And then add new elements in a loop that traverses the copy

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

Bookmate
Health Samurai
Dualboot
ABBYY
Suggested learning programs
profession
new
Developing web applications with Django
10 months
from scratch
under development
Start at any time

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.