BeginnerPython · 39 min · 24 challenges

Loops: Beginner

Spotify Wrapped lands every December, and behind each listener's card sits the same arithmetic repeated for hundreds of millions of accounts: total the minutes played, count the artists, find the one most-played song. That code is written once and run for every account. Inside it, one loop walks every play record, carries a running total, and stops the moment it has what it needs. This lesson builds that loop.

Iterating with for Loops

Daily Life
Interviews
A loop runs the same block of code once for every item in a sequence. Greeting 3 friends takes 3 print statements. Greeting 3,000 customers takes a loop, and the loop is the same 2 lines either way, because the number of passes comes from the data and the code stays fixed.

The for loop names a variable, then a sequence. for fruit in fruits: reads as "for each fruit in fruits". On every pass, Python assigns the next item to fruit and runs the indented lines under the colon. When the sequence runs out, the loop is over.

A list is a sequence of values written between square brackets and separated by commas, such as ["apple", "banana", "cherry"]. It keeps its items in the order they were written, and a loop visits them in that order: first item first, last item last.

1fruits = ["apple", "banana", "cherry"]
2
3for fruit in fruits:
4 print("I like", fruit)
5
6print("Done!")
fruit=
fruits
[
]
012
output0 lines
fruits is a new list that holds 'apple', 'banana', 'cherry'
1/10

The loop body is 1 line, and it runs 3 times. On the first pass fruit holds "apple", on the second "banana", on the third "cherry". After the third pass there is no fourth item, so Python moves to the first line at the loop's own indentation. "Done!" prints once, after the 3 greetings, because it sits outside the body.

Passfruit holdsLine printed
1"apple"I like apple
2"banana"I like banana
3"cherry"I like cherry
after the loop"cherry" (unchanged)Done!

Strings are sequences too

A string is a sequence of characters, so a for loop over a string hands you 1 character per pass. "Python" has 6 characters, so the body below runs 6 times and prints 6 lines of 1 letter each. The loop variable holds a fresh 1-character string on every pass, and the original string is untouched.
1word = "Python"
2
3for char in word:
4 print(char)
char=
wordstr0 chars
“
”
012345
output0 lines
word starts at 'Python'
1/15

Carrying a result across passes

Printing each item is the smallest thing a loop can do. More often the loop builds one answer out of many items: a total, a count, a largest value. The pattern has 3 parts: a variable created before the loop with a starting value, a line inside the loop that updates it, and a line after the loop that uses the finished result.
1numbers = [10, 20, 30, 40, 50]
2
3# Calculate the sum
4total = 0
5for num in numbers:
6 total = total + num
7
8print("Sum:", total)
9
10count = 0
11for num in numbers:
12 if num > 25:
13 count = count + 1
14
15print("Numbers > 25:", count)
total=
num=
count=
numbers
[
]
01234
output0 lines
numbers is a new list that holds 10, 20, 30, 40, 50
1/31
Passnumtotal after the pass
11010
22030
33060
440100
550150

total = 0 before the loop matters. If that line sat inside the body, total would reset to 0 on every pass and the final answer would be 50, the last number alone. The second loop counts instead of sums: count goes up by 1 only on passes where the if is true, which happens for 30, 40 and 50, so it prints 3.

TIP
Indentation decides what repeats. Every line indented under the for runs once per item. The first line back at the loop's own indentation runs once, after the last pass, no matter how many items there were.

Practice: counting letters

Run the program below in your head before you reveal its output. The if inside the loop fires only on passes where the character is "a". "banana" has 6 characters, so the body runs 6 times, and count moves on 3 of those passes.
word = "banana"
count = 0
for letter in word:
if letter == "a":
count = count + 1
print("a appears", count, "times")
>>>Output
a appears 3 times
Where a print sits decides how often it runs. Indented under the for, it shows the accumulator after every pass, which is how you watch a running total grow. Back at the loop's own indentation, it runs once and shows only the finished value. The question below puts the print inside the body.
Multiple Choice

The print sits inside the loop body. What does this program print?

total = 0
for n in [2, 4, 6]:
total = total + n
print(total)

Writing an accumulator from scratch means filling 3 slots in the right places: the starting value on the line above the for, the list's name after in on the for line, and the loop variable's name inside the body, spelled exactly as the for line spells it. A sum starts from 0, since adding 0 changes nothing.

A misplaced starting line fails without an error message. Python runs it on every pass, so the accumulator restarts each time, and the value left at the end reflects only the final pass. When a count comes out smaller than the data says it should, check whether its starting assignment sits inside the body.

range() Function

Daily Life
Interviews

A for loop needs a sequence to walk. When the sequence you want is a run of numbers, range() builds it for you. range(5) produces 0, 1, 2, 3, 4: it starts at 0, climbs by 1, and stops before 5. The number you pass is the stop, and the stop itself is never produced.

1# Print 0 to 4
2for i in range(5):
3 print(i)
i=
output0 lines
i takes 0, item 1 of range(5)
1/12
The loop makes 5 passes, one per number, and the last printed value is 4. This lines up with how positions are counted in Python: the first position is 0, so the 5 positions of a 5-item sequence are 0 through 4, and range(5) produces exactly those 5 numbers.

Start, stop and step

range() accepts 1, 2 or 3 numbers. A single number is the stop, and the start defaults to 0. Given 2, range reads them as the start and the stop. A third number is the step: how far each produced number is from the one before it. A negative step counts down.

CallProducesHow many
range(5)0, 1, 2, 3, 45
range(2, 6)2, 3, 4, 54
range(0, 10, 2)0, 2, 4, 6, 85
range(10, 0, -3)10, 7, 4, 14
range(3, 3)nothing0
range(5, 2)nothing0
The stop stays excluded in every form. range(2, 6) ends at 5. range(10, 0, -3) keeps producing values while they are above 0, so 1 is the last one and -2 is never reached. range(5, 2) uses the default step of 1 and can't climb from 5 to a value below 2, so it produces nothing, and a loop over it runs its body 0 times without an error.
for i in range(2, 6):
print("i is", i)
for i in range(10, 0, -3):
print("down to", i)
>>>Output
i is 2
i is 3
i is 4
i is 5
down to 10
down to 7
down to 4
down to 1

Repeating something n times

Sometimes the numbers themselves are beside the point and you want the body to run a fixed number of times. range(3) still produces 0, 1 and 2, but the body never reads them. The convention is to name the variable _ to signal to anyone reading the code that nothing uses it.

for _ in range(3):
print("Knock")

Getting the stop right

When a sum should run from 1 to 10 inclusive, the stop is 11. Being off by 1 at the stop is the most common range mistake. The fix is a question: which value should be the last one produced? Pass 1 more than that as the stop. For a step of 2 running from 0 to 20 inclusive, the stop is 21, and 20 is the last value produced.
total = 0
for n in range(1, 11):
total = total + n
print("1 to 10 sums to", total)
evens = 0
for n in range(0, 21, 2):
evens = evens + 1
print(evens, "even numbers from 0 to 20")
>>>Output
1 to 10 sums to 55
11 even numbers from 0 to 20
Rules range() always follows
  • ▸The start is included and the stop is excluded: range(2, 6) produces 2, 3, 4, 5.
  • ▸range(n) produces exactly n numbers, 0 through n - 1, so the body runs n times.
  • ▸A step that moves away from the stop, or a start already past the stop, produces nothing and the loop body runs 0 times.
TIP
To count down, the start must be larger than the stop and the step must be negative. range(0, 10, -1) produces nothing, because stepping by -1 from 0 never reaches a value above 10.
Multiple Choice

How many lines does this loop print?

for i in range(3, 12, 4):
print(i)

Working backwards from a wanted sequence to a range call takes 3 readings. The first value is the start. The gap between neighbours is the step. The stop is any number past the last value and at most 1 step beyond it, and last value + 1 is the safe choice. For 3, 6, 9 that gives range(3, 10, 3).

A countdown reads the same way with a negative step. The start is the first number printed and the step is -1. The excluded stop now sits on the low side, so it goes 1 below the last number you want: to end on 3, stop at 2. range(9, 2, -1) produces 9 down to 3.

Loops with while

Daily Life
Interviews

A for loop knows how many passes it will make before it starts: 1 per item. A while loop does not. It checks a condition, runs the body if the condition is True, then returns to the condition and checks again. It stops the first time the check comes back False, and the number of passes is whatever that takes.

1count = 0
2
3while count < 5:
4 print("Count is", count)
5 count = count + 1
6
7print("Loop finished!")
count=
output0 lines
count starts at 0
1/19
Checkcount < 5Body printscount after the body
10 < 5 is TrueCount is 01
21 < 5 is TrueCount is 12
32 < 5 is TrueCount is 23
43 < 5 is TrueCount is 34
54 < 5 is TrueCount is 45
65 < 5 is Falsenothing, loop ends5
The check runs 6 times and the body runs 5 times. On the sixth check count is 5, 5 < 5 is False, and Python jumps to the line after the loop. A while loop that ends because its condition fails has this shape: the condition is tested 1 more time than the body runs, and the final test is the one that fails. A break statement can end a loop before its condition ever fails.

Setup, condition and progress in a while loop

Setup, before the loop: give the variable the condition depends on its starting value, such as count = 0.
Setup, before the loop: give the variable the condition depends on its starting value, such as count = 0.
Condition, on the while line: an expression that is True while the loop should keep going.
Condition, on the while line: an expression that is True while the loop should keep going.
Progress, inside the body: a line that moves the variable toward making the condition False.
Progress, inside the body: a line that moves the variable toward making the condition False.
The progress line is the one that gets dropped. Without count = count + 1, count stays 0, 0 < 5 stays True, and the loop prints "Count is 0" without end. A program stuck like this never reaches the line after the loop, and the only way to stop it is to stop the program from outside.
count = 0
while count < 5:
print("Count is", count)
print("Loop finished!")

When the number of passes is unknown

A while loop is the better fit when the stopping point depends on the values, which a range cannot know in advance. How many times must 1 be doubled before it passes 100? The loop can find out by doubling until the condition fails.
amount = 1
doublings = 0
while amount < 100:
amount = amount * 2
doublings = doublings + 1
print(doublings, "doublings reach", amount)
>>>Output
7 doublings reach 128
The amounts go 1, 2, 4, 8, 16, 32, 64, 128. The loop doubles 7 times, and the check 128 < 100 is the one that fails. The final amount is 128, past the target: the body runs in full on the pass that crosses 100, and only the next check stops the loop. A while loop can overshoot its target by up to 1 pass's worth of change: here the last pass moved from 64 to 128, and 128 lands 28 past 100.

Zero passes

Because the check comes before the body, a while loop whose condition is False at the start runs its body 0 times. Nothing inside it prints, and every variable keeps the value it had before the while line.
n = 10
while n < 5:
print("inside")
n = n + 1
print("n is", n)
>>>Output
n is 10
✓Reach for for
  • You have a list or a string to walk through.
  • You know the number of passes up front, so range(n) fits.
  • Python moves to the next item for you, so there is no progress line to forget.
✗Reach for while
  • The stopping point depends on values computed during the loop.
  • You repeat until a target is reached, such as doubling past 100.
  • You write the progress line yourself, and the loop runs until your condition fails.
Multiple Choice

What does this program print?

x = 1
while x < 20:
x = x * 3
print(x)

The comparison on the while line decides the last value the body sees. while n > 0 lets the body run for 1 and stops when n is 0. while n >= 0 also lets 0 through, so the body runs 1 extra time. When a loop prints 1 value too many or too few, test the boundary value against the condition by hand.

A target such as "the first value that is at least X" turns into a condition by asking when the loop should keep going: while the value is still short of X. To find the first multiple of 3 that is at least 20, start from m = 0, loop while m < 20: with m = m + 3 as the progress line, and the loop stops on 21.

Using break and continue

Daily Life
Interviews

Inside a loop body, 2 statements can change the loop's course. break ends the loop at once: the rest of the body is skipped, no more passes happen, and Python moves to the first line after the loop. continue ends only the current pass: the rest of the body is skipped, and the loop moves to the next item, or in a while loop, back to the condition check.

break: stop searching once found

1# Find first negative number
2numbers = [1, 5, 3, -2, 7, 8]
3
4for num in numbers:
5 if num < 0:
6 print("Found negative:", num)
7 break
8 print("Checked:", num)
9
10print("Search complete")
num=
numbers
[
]
012345
output0 lines
numbers is a new list that holds 1, 5, 3, -2, 7, 8
1/16
The list has 6 numbers, and only 4 passes run. The first 3 passes fail the if, print "Checked:", and move on. On the fourth pass -2 passes the if, "Found negative: -2" prints, and break ends the loop before the "Checked:" line runs and before 7 and 8 are ever visited. "Search complete" prints because it sits after the loop at the outer indentation, and break only skips what's inside the loop.
numnum < 0What happens
1Falseprints Checked: 1
5Falseprints Checked: 5
3Falseprints Checked: 3
-2Trueprints Found negative: -2, then break
7, 8never testedloop already ended

continue: skip this one

1# Print only positive numbers
2numbers = [1, -2, 3, -4, 5]
3
4for num in numbers:
5 if num < 0:
6 continue
7 print(num)
8
9print("Done")
num=
numbers
[
]
01234
output0 lines
numbers is a new list that holds 1, -2, 3, -4, 5
1/19
All 5 passes happen here. On the passes for -2 and -4, continue jumps straight to the next item, so the print(num) below it never runs for those 2 values. The output is 1, 3, 5 on 3 lines, then "Done". Compare that with break, which would have stopped the whole loop at -2 and printed only 1.
✓break
  • Ends the entire loop.
  • No further items are visited.
  • Execution continues at the first line after the loop.
  • Use it when the answer is found and the rest is wasted work.
✗continue
  • Ends only the current pass.
  • The next item is visited as usual.
  • Execution jumps to the top of the loop.
  • Use it to skip items that fail a test while keeping the loop running.

Did the loop find it?

After a loop that uses break, the code following it cannot tell on its own whether the loop stopped early or ran out of items. A flag variable records the answer: set it to False before the loop, set it to True right before the break, and test it afterwards with an if. If the loop finishes without ever reaching the break, the flag is still False.
1# Search with a found flag
2numbers = [1, 3, 5, 7, 9, 11]
3target = 7
4found = False
5
6for num in numbers:
7 if num == target:
8 found = True
9 break
10
11if found:
12 print("Found", target, "in the list!")
13else:
14 print(target, "not found")
15
16# Same search, target not present
17target = 8
18found = False
19for num in numbers:
20 if num == target:
21 found = True
22 break
23
24if found:
25 print("Found", target)
26else:
27 print(target, "not found")
target=
found=
num=
numbers
[
]
012345
output0 lines
numbers is a new list that holds 1, 3, 5, 7, 9, 11
1/33

break inside while

while True: is a loop whose condition never fails on its own, so a break inside it is the only way out. The pattern suits loops where the exit test belongs in the middle of the body, after some work has been done on the pass, rather than at the top.

guess = 0
while True:
guess = guess + 7
if guess > 30:
break
print("stopped at", guess)
>>>Output
stopped at 35
The check guess > 30 fails for 7, 14, 21 and 28, so those passes finish and the loop goes round again. At 35 the check passes, break fires, and the print after the loop shows 35.

continue can skip the progress line in while

In a while loop, continue jumps back to the condition check. If the progress line sits after the continue, the pass skips it, the condition sees the same value again, and the loop never ends. In a for loop this cannot happen, because Python itself moves to the next item.
n = 0
while n < 5:
if n == 2:
continue
print(n)
n = n + 1
✓Do
  • Use break the moment a search succeeds, so the remaining items are never visited.
  • Pair break with a flag when code after the loop needs to know whether it fired.
  • Put the progress line before any continue in a while loop.
✗Don't
  • Expect lines after a break inside the body to run; they are skipped on that pass.
  • Use continue where wrapping the rest of the body in an if would read better.
  • Rely on the loop variable alone to tell you whether a break happened.
Multiple Choice

The remainder n % 3 is 0 for multiples of 3. What does this loop print?

for n in range(1, 7):
if n % 3 == 0:
continue
print(n)

The order of lines inside the body decides whether the item that triggers break gets processed. When the if holding break comes before the print, the triggering item ends the loop without being printed. When the print comes first, that item is printed and then the loop ends. Either way, the line after the loop runs once.

Swapping continue for break turns a filter into a stop sign. In a loop that sums only positives, continue drops each negative and keeps adding the rest. A break in that spot ends the sum at the first negative, so every positive after it is lost and the total comes out low with no error to warn you.

Loop Variable Scope

Daily Life
Interviews
A loop variable in Python is an ordinary variable. The for loop assigns to it on every pass, and the loop ending does not delete it or reset it. Whatever value it was given last is still there, and code after the loop can read it. This is useful, and it is also a source of surprises when you expect the variable to vanish.
1for i in range(3):
2 print("inside", i)
3print("after", i)
4
5total = 0
6for n in [4, 9, 2]:
7 total = total + n
8print("last n", n, "total", total)
9
10count = 10
11while count < 13:
12 count = count + 1
13print("count", count)
i=
total=
n=
count=
output0 lines
i takes 0, item 1 of range(3)
1/27

Each loop variable survives its loop and holds the last value assigned to it.

LoopLast assignment to the variableValue after the loop
for i in range(3)i = 2 on the third pass2
for n in [4, 9, 2]n = 2 on the third pass2
while count < 13count = 13 inside the body13
The first loop's last assignment was i = 2, so "after 2" prints. The second loop's last item was 2, so n is 2 while total holds the full sum of 15. The while loop reads differently: count is a variable the body increments, and its final value is the first one that made count < 13 False. That is why it reads 13. When a while loop ends because its check fails, the counter holds the value that failed it; if a break ends the loop, the counter keeps whatever the body last assigned.

break leaves the variable on the found item

When break fires, the loop variable holds the item of the pass that triggered it, because no later pass happens to overwrite it. A search loop can hand its result to the code after it this way: the loop variable is the thing that was found.
for n in [3, 8, 5, 12, 6]:
if n > 9:
break
print(n)
>>>Output
12
Values 3, 8 and 5 fail the if, and 12 passes it. The break fires while n is 12, so 6 is never assigned and the print shows 12. Without the break, the loop would run to the end and the same print would show 6, the last item.

A loop that never runs

If the sequence is empty, the body runs 0 times and the loop variable is never assigned. Reading it afterwards raises a NameError if no earlier line created it, the same error you get from any variable that was never assigned. If an earlier line did create it, it keeps that earlier value, because the loop never touched it.

for item in []:
print(item)
print(item)
item = "nothing"
for item in []:
print("inside")
print(item)
>>>Output
nothing

Reusing a name

Loops that use the same variable name share 1 variable. After the second loop, the name holds the second loop's last value, and the first loop's final value is gone. Distinct names such as price and name, or row and col, show at a glance which loop last wrote to a variable, and they keep a later loop from quietly overwriting a value you still need.
Predicting a value after a loop
  • ▸A for loop variable holds the last item visited: the final item if the loop ran to the end, or the item that triggered break.
  • ▸If a while loop ends because its condition fails, the counter holds the first value that made it False; if break ends it, the counter holds what the last pass assigned.
  • ▸A loop over an empty sequence never assigns its variable, so the variable is either missing or still holds an earlier value.
  • ▸Accumulators like total keep whatever the last pass left in them, and nothing resets them.
Multiple Choice

What does this program print?

n = 1
while n * n < 50:
n = n + 1
print(n)

Predicting a for variable after a break means finding the first item, in list order, that passes the if, and stopping there. Later items are never assigned, even ones that would also pass. Over [2, 15, 30] with a break on n > 10, n ends at 15, and 30 never reaches the variable.

When a printed value belongs to the wrong loop, look for a name that 2 loops share. The second loop's assignments land in the same variable, so once it ends, the first loop's value is gone. Giving each loop a variable named for its own data, such as name and score, keeps both values.

❯❯❯PUTTING IT ALL TOGETHER

> Picture 1 listener's Spotify Wrapped card computed from their play records by a short program. One for loop walks the records and carries a running total of minutes, the way the accumulate example carried its sum. A second loop counts how many records clear a 30-second mark, skipping the rest with continue, because a track skipped after 5 seconds should not count as a play. A while loop keeps pulling the next page of records until a page comes back empty, since nobody knows up front how many pages a heavy listener has. And a search for the first record from a brand-new artist uses break the moment it finds one, with a found flag so the card can say whether that discovery ever happened.

The running total of minutes is the accumulator pattern from section 0: a variable created before the loop, updated on every pass, read once after.
Skipping plays under 30 seconds is continue from section 3: the pass ends early, the loop keeps going, and the count only moves for plays that qualify.
Paging until an empty page arrives is a while loop from section 2, because the number of passes depends on the data and cannot be written as a range.
Stopping at the first new-artist record is break from section 3, and the found flag answers the question the loop variable alone cannot: did the break ever fire?
After the search loop, the loop variable holds the record that triggered the break, which is section 4's rule for predicting a variable's value once a loop ends.
KEY TAKEAWAYS
A for loop runs its indented body once per item of a list or string, assigning each item to the loop variable in order.
range(start, stop, step) produces numbers from start up to but never including stop; range(n) gives exactly n numbers, 0 through n - 1.
A while loop tests its condition before every pass; when it ends because the condition fails, the condition is tested 1 more time than the body runs.
Every while loop needs setup, a condition and a progress line; without progress the condition never changes and the loop never ends.
break ends the whole loop and jumps to the line after it; continue ends only the current pass.
Loop variables outlive their loops: a for variable holds the last item visited, and when a while loop ends because its check fails, its counter holds the value that failed it.

Make Python repeat itself: walk lists and strings, count with range, loop while a condition holds, and exit on demand.

Category
Python
Difficulty
beginner
Duration
39 minutes
Challenges
24 hands-on challenges

Topics covered: Iterating with for Loops, range() Function, Loops with while, Using break and continue, Loop Variable Scope

Lesson Sections

  1. Iterating with for Loops (concepts: Iteration)

    A loop runs the same block of code once for every item in a sequence. Greeting 3 friends takes 3 print statements. Greeting 3,000 customers takes a loop, and the loop is the same 2 lines either way, because the number of passes comes from the data and the code stays fixed. Strings are sequences too A string is a sequence of characters, so a for loop over a string hands you 1 character per pass. "Python" has 6 characters, so the body below runs 6 times and prints 6 lines of 1 letter each. The loo

  2. range() Function (concepts: Iteration)

    The loop makes 5 passes, one per number, and the last printed value is 4. This lines up with how positions are counted in Python: the first position is 0, so the 5 positions of a 5-item sequence are 0 through 4, and range(5) produces exactly those 5 numbers. Start, stop and step The stop stays excluded in every form. range(2, 6) ends at 5. range(10, 0, -3) keeps producing values while they are above 0, so 1 is the last one and -2 is never reached. range(5, 2) uses the default step of 1 and can't

  3. Loops with while (concepts: Conditional Loops)

    The check runs 6 times and the body runs 5 times. On the sixth check count is 5, 5 < 5 is False, and Python jumps to the line after the loop. A while loop that ends because its condition fails has this shape: the condition is tested 1 more time than the body runs, and the final test is the one that fails. A break statement can end a loop before its condition ever fails. Setup, condition and progress in a while loop The progress line is the one that gets dropped. Without count = count + 1, count

  4. Using break and continue (concepts: Loop Control)

    break: stop searching once found The list has 6 numbers, and only 4 passes run. The first 3 passes fail the if, print "Checked:", and move on. On the fourth pass -2 passes the if, "Found negative: -2" prints, and break ends the loop before the "Checked:" line runs and before 7 and 8 are ever visited. "Search complete" prints because it sits after the loop at the outer indentation, and break only skips what's inside the loop. continue: skip this one All 5 passes happen here. On the passes for -2

  5. Loop Variable Scope (concepts: Iteration)

    A loop variable in Python is an ordinary variable. The for loop assigns to it on every pass, and the loop ending does not delete it or reset it. Whatever value it was given last is still there, and code after the loop can read it. This is useful, and it is also a source of surprises when you expect the variable to vanish. The first loop's last assignment was i = 2, so "after 2" prints. The second loop's last item was 2, so n is 2 while total holds the full sum of 15. The while loop reads differe