Loops in Python

By the Syncfusion DevTutorials team · Last updated

Repeating work with for and while, counting with range(), break, continue and pass, nested loops, avoiding infinite loops, and the loop else.

Imagine marking thirty exam papers.

You pick up a paper, add up the marks, write the total on the front, and put it on the pile. Then you pick up the next one and do exactly the same thing. Thirty times.

The job is one set of steps, repeated once for each paper. You do not write out thirty separate sets of instructions.

Programs repeat work the same way, and the tool is called a loop.

The same work, once for each mark

marks = [78, 85, 60]

for mark in marks:
    print("Mark:", mark, "- Passed:", mark >= 35)

Two lines of code did the work three times. Add a fourth mark to the list and run it again — the loop handles it without a single change.

What You Will Learn

In this lesson, you will learn:

  • How to repeat work once for each item in a list
  • How to count with range(), including counting backwards
  • How to repeat while something stays true
  • How to leave a loop early, skip one turn, or do nothing
  • How to put one loop inside another
  • What an infinite loop is and how to avoid writing one
  • The else that can follow a loop, and when it runs

A loop runs the same block of code once for each item, or until a test stops being true.

Introduction to Loops

What Are Loops?

A loop repeats a block of code. Each repeat is called an iteration.

You will also hear the word turn used in this lesson. A turn and an iteration are the same thing: one pass through the loop body.

Why Loops Are Used

Without a loop, repeated work has to be written out in full.

Three marks, written out three times

marks = [78, 85, 60]

print(marks[0])
print(marks[1])
print(marks[2])

That works for three marks. For thirty it is unreadable, and for a list whose length you do not know in advance it is impossible.

Any number of marks, one block of code

marks = [78, 85, 60, 92, 45, 67, 88]

for mark in marks:
    print(mark)

The same two lines handle seven marks, or seven hundred.

Types of Loops in Python

Python has two.

LoopUse it whenStops when
foryou know what you are going through — a list, a range, some textthe items run out
whileyou do not know how many turns it will takethe condition becomes false

A rough rule: counting or going through a collection is a for. Waiting for something to change is a while.

You will meet both loop types in this lesson, starting with for.

for Loop

What Is a for Loop?

A for loop takes each item of a collection in turn and runs its block once for each.

for variable in collection:
    code that runs once per item

The line ends in a colon, and the block is indented, exactly like an if.

One turn for each item

subjects = ["Maths", "Science", "English"]

for subject in subjects:
    print("Marking", subject)

print("All subjects marked")

The last line is not indented, so it runs once, after the loop has finished.

Iterating Over Sequences

A for loop works on anything Python can take items from one at a time.

A list, some text, and a pair

for mark in [78, 85]:
    print("Mark:", mark)

for letter in "Asha":
    print("Letter:", letter)

for value in ("maths", 78):
    print("Value:", value)

Text gives you one character at a time, which is often a surprise the first time you see it.

A dictionary gives you its keys:

Going through a dictionary

report = {"maths": 78, "science": 85}

for subject in report:
    print(subject, "->", report[subject])

.items() gives you the key and the value together, which usually reads better:

Keys and values together

report = {"maths": 78, "science": 85}

for subject, mark in report.items():
    print(subject, "->", mark)

Loop Variables

The name after for is the loop variable. It holds one item at a time, and Python gives it a new value on every turn.

You choose the name. Choose one that says what the item is.

A name that explains itself

marks = [78, 85, 60]

for mark in marks:
    print(mark, "out of 100")

for mark in marks reads as a sentence. for m in marks does not.

The loop variable still exists after the loop ends, holding the last item:

The variable outlives the loop

marks = [78, 85, 60]

for mark in marks:
    pass

print("Last mark:", mark)

That is occasionally useful and more often a source of confusion, so do not rely on it.

range() Function

Creating Ranges

range() produces a run of whole numbers. It is what you use when you want to count rather than go through a collection.

Counting from zero

for number in range(5):
    print(number)

range(5) gives 0, 1, 2, 3, 4. It starts at 0 and stops before 5, so there are exactly five numbers and 5 itself is not one of them.

Start, Stop, and Step Values

range() takes up to three numbers.

range(stop)
range(start, stop)
range(start, stop, step)

All three forms

print(list(range(5)))
print(list(range(1, 6)))
print(list(range(0, 10, 2)))

list() is used here only so the numbers can be printed in one go. In a loop you do not need it.

The stop value is never included. range(1, 6) ends at 5.

A negative step counts backwards:

Counting down

for number in range(5, 0, -1):
    print(number)

print("Lift off")

Getting the direction wrong gives an empty range rather than an error:

A range that produces nothing

print(list(range(5, 0)))

for number in range(5, 0):
    print("This never prints")

print("The loop body never ran")

range(5, 0) counts up from 5 towards 0, which it can never reach, so it produces nothing at all. The loop runs zero times and the program carries on with no complaint.

Using range() with Loops

Counting from 1 is the usual reason to give a start value:

Numbering the subjects

subjects = ["Maths", "Science", "English"]

for number in range(1, len(subjects) + 1):
    print(number, subjects[number - 1])

That works, but Python has a neater way when you need the position and the item together:

enumerate gives position and item

subjects = ["Maths", "Science", "English"]

for number, subject in enumerate(subjects, start=1):
    print(number, subject)

No arithmetic on the index, so no chance of an off-by-one mistake.

Use range() when you want numbers. Use the collection itself when you want its items, and enumerate() when you want both.

while Loop

What Is a while Loop?

A while loop repeats as long as its condition stays true.

while condition:
    code that runs while the condition is true

Repeating while something is true

lives = 3

while lives > 0:
    print("Lives left:", lives)
    lives -= 1

print("Game over")

The condition is checked before each turn. When lives reaches 0 the test fails and the loop ends.

If the condition is false at the start, the body never runs at all:

A loop that never starts

lives = 0

while lives > 0:
    print("This never prints")

print("Finished without looping")

Loop Conditions

The condition is any expression that gives True or False, exactly as in an if.

Counting up to a total

total = 0
marks = 0

while total < 200:
    marks += 50
    total += marks
    print("Added", marks, "- total now", total)

print("Final total:", total)

Updating Conditions

Something inside the loop must change what the condition depends on. This is the whole difference between a loop that ends and one that does not.

The line that makes the loop end

countdown = 3

while countdown > 0:
    print(countdown)
    countdown -= 1

print("Done")

Take out countdown -= 1 and countdown stays 3 for ever. The condition stays true, and the loop never stops.

A safe habit when you write a while: write the line that changes the condition at the same moment you write the condition itself, before you write anything else in the body.

Loop Control Statements

break

break leaves the loop immediately. Nothing after it in the body runs, and no further turns happen.

Stopping as soon as you find it

marks = [78, 85, 20, 60]

for mark in marks:
    if mark < 35:
        print("Found a failing mark:", mark)
        break
    print("Checked", mark)

print("Search finished")

The loop stopped at 20 and never looked at 60.

break is how you stop as soon as you have your answer, instead of walking through the rest of a list for nothing.

continue

continue skips the rest of this turn and moves on to the next one. The loop itself keeps going.

Skipping one turn

marks = [78, 85, 20, 60]

for mark in marks:
    if mark < 35:
        continue
    print("Passed:", mark)

print("Finished")

The failing mark was skipped, and the loop carried on to 60.

StatementWhat it does
breakleaves the loop completely
continueskips the rest of this turn, starts the next
passdoes nothing at all

pass

pass does nothing. It exists because Python needs a block after a colon, and sometimes you have nothing to put there yet.

A placeholder that keeps the program running

marks = [78, 85, 60]

for mark in marks:
    if mark >= 80:
        pass
    else:
        print(mark, "is below 80")

Without pass, the empty if block would stop the program with an IndentationError.

Use it as a reminder of a branch you intend to fill in. It is not a way to skip a turn — that is continue.

Nested Loops

Nested for Loops

A loop inside a loop is a nested loop. The inner loop runs all the way through on every single turn of the outer one.

Every subject for every student

students = ["Asha", "Ravi"]
subjects = ["Maths", "Science"]

for student in students:
    for subject in subjects:
        print(student, "-", subject)

Two students and two subjects give four lines. The counts multiply: ten students and ten subjects would be a hundred.

A table built from two loops

for row in range(1, 4):
    line = ""
    for column in range(1, 4):
        line += str(row * column) + "\t"
    print(line)

The inner loop builds one row. The outer loop moves to the next row.

Nested while Loops

The same idea works with while, and now both counters have to be updated.

Two counters, both reset and both updated

row = 1

while row <= 3:
    column = 1
    while column <= 3:
        print(row, column, end="  ")
        column += 1
    print()
    row += 1

Notice column = 1 sits inside the outer loop. It has to be reset at the start of every row, or the inner loop would run only once and then find its condition already false.

A nested loop multiplies the work. Two lists of 1,000 items each give a million turns. Before nesting, ask whether one pass would do.

Infinite Loops

What Is an Infinite Loop?

An infinite loop is a loop whose condition never becomes false, so it never ends.

In a browser page like this one, an infinite loop freezes the tab. On your own computer you stop it with Ctrl+C. Either way, nothing else happens until you do.

So the example below is deliberately not runnable — reading it is enough:

lives = 3

while lives > 0:
    print(lives)

lives is never changed, so lives > 0 is true for ever.

Common Causes

CauseExampleFix
Nothing updates the conditionwhile lives > 0: with no lives -= 1change the value inside the loop
Updating in the wrong directioncountdown += 1 when counting down to zerocountdown -= 1
The update is skipped by a continuecontinue placed before the counter changesupdate the counter before the continue
The update sits outside the loopthe counter line is not indentedindent it into the loop body
A condition that cannot be reachedwhile total != 10: adding 3 each timeuse >= or <= rather than !=

The last one is the sneaky one. Counting 0, 3, 6, 9, 12 skips straight past 10, so total != 10 is true for ever.

Preventing Infinite Loops

Three habits deal with almost all of them.

Write the update with the condition. The moment you write while countdown > 0:, write countdown -= 1 before anything else.

Prefer for when you can. A for loop over a list or a range ends by itself, because the items run out.

A loop that cannot run for ever

for countdown in range(3, 0, -1):
    print(countdown)

print("Done")

Give an open-ended loop a limit. When a loop waits for something that might never happen, count the turns and stop at a sensible number.

A guard that stops a runaway

MAX_TRIES = 5

total = 0
tries = 0

while total != 10 and tries < MAX_TRIES:
    total += 3
    tries += 1
    print("Try", tries, "- total", total)

if total != 10:
    print("Gave up after", tries, "tries")

The condition total != 10 can never be satisfied by adding 3 at a time. Without the guard this loop would run for ever; with it, the program says so and moves on.

In a while loop, prefer < or > over !=. A counter can step straight past an exact value and never come back to it.

Loop else Clause

for-else

A loop can have an else. It runs when the loop finished normally — that is, when no break happened.

The else runs when nothing broke out

marks = [78, 85, 60]

for mark in marks:
    if mark < 35:
        print("Found a failing mark")
        break
else:
    print("Every mark passed")

No mark was below 35, so the loop ran to the end and the else ran.

while-else

The same rule applies to a while.

A while loop with an else

countdown = 3

while countdown > 0:
    print(countdown)
    countdown -= 1
else:
    print("Countdown finished without interruption")

When else Executes

This is the part people get wrong, so it is worth stating plainly.

The else of a loop runs when the loop ends on its own. It does not run if a break stopped it.

It is nothing to do with the loop body being empty, and nothing to do with the condition being false at the start.

A break skips the else

marks = [78, 20, 60]

for mark in marks:
    if mark < 35:
        print("Found a failing mark:", mark)
        break
else:
    print("Every mark passed")

print("Checked")

The break fired, so the else was skipped and only Checked followed.

A loop that never runs at all still counts as finishing normally:

No turns at all, and the else still runs

for mark in []:
    print("This never prints")
else:
    print("The else still runs")

The honest summary: read else here as "if no break". The keyword is a poor name, and even experienced Python programmers avoid it for that reason. The same job is often clearer with a flag or a function.

Common mistakes

Each row is one mistake. The middle column is what you will actually see on screen.

MistakeWhat you seeWhy it happensFix
Nothing updates the while conditionThe page or terminal freezesThe condition stays true for everChange the value inside the loop body
The update sits outside the loopThe loop never endsThe line is not indented into the bodyIndent it into the loop
Expecting range(5) to include 5Four turns where you wanted fiverange() stops before the stop valuerange(1, 6) for 1 to 5
range(5, 0) with no stepThe loop body never runs, and no errorCounting up from 5 can never reach 0range(5, 0, -1)
Using != in a counting conditionThe loop never endsThe counter steps straight past the valueUse < or > instead
Forgetting to reset the inner counterThe inner loop runs only onceIts condition is already false after the first rowReset it inside the outer loop
continue placed before the updateThe loop never endsThe line that changes the condition is skippedUpdate the counter before the continue
Expecting pass to skip a turnNothing is skippedpass does nothing at allUse continue
Expecting the loop else to always runA message that disappears sometimeselse is skipped whenever a break firesRead it as "if no break"
Changing a list while looping over itItems quietly skippedThe positions shift under the loopLoop over a copy, or build a new list
Forgetting the colonSyntaxError: expected ':'for and while both open a blockEnd the line with :

What to Remember

  • A loop runs the same block of code once for each item, or until a test stops being true.
  • A for loop goes through a collection and ends when the items run out.
  • A while loop repeats while its condition is true, and checks the condition before each turn.
  • range(stop) starts at 0. range(start, stop) never includes the stop value. A negative step counts backwards.
  • enumerate() gives the position and the item together, with no arithmetic on the index.
  • break leaves the loop. continue skips the rest of this turn. pass does nothing.
  • A nested loop runs the inner loop fully on every turn of the outer one, so the work multiplies.
  • Something inside a while loop must change what the condition depends on, or it never ends.
  • Prefer < or > to != in a counting condition, and give an open-ended loop a limit.
  • The else after a loop means "if no break", and it runs even when the loop had no turns at all.

Next: Functions