The while Loop and the Accumulator Pattern
Context
A while loop repeats a block for as long as a condition stays true. The accumulator pattern pairs with it, one name holding a running result that each pass updates, so that many small steps add up to one answer.
Running totals are everywhere in this work. A sum of prices on the way to a mean, a count of rows that failed validation, a best-score-so-far that survives across attempts, all of them are one value carried forward and updated repeatedly. The while form specifically fits the case where you do not know in advance how many passes it takes, such as reading until the data runs out or retrying until a value falls inside range.
The failure here is the loop that never ends. A condition that stays true, with nothing in the body to end the loop, leaves the program spinning forever, producing no result and no error, and it has to be killed from the terminal. The mirror failure is the accumulator reset in the wrong place, restarting the total on every pass so the final answer reflects only the last row. The previous lesson made a decision once, this lesson makes it repeatedly.
Goal
- Write a
whileloop that is guaranteed to terminate. - Maintain a running total or count across iterations using the accumulator pattern.
- Identify the loop condition and the update that eventually makes it false.
- Diagnose an infinite loop by naming the condition that never becomes false.
- Combine a loop with a conditional to count how many values pass a test.
Prerequisites
Neither is required and nothing below assumes you opened them. They are here only if you would rather see the mechanism before you build it, and Theory teaches it from nothing either way.
- YouTube - "Python Tutorial for Beginners 7: Loops and Iterations - For/While Loops" by Corey Schafer. The
whileportion, on the loop and avoiding infinite loops. Watch for one picture, a condition re-checked before every single pass. - Official docs - Python Language Reference, "The while statement". The precise definition of when the body runs and when it stops.
Table of Contents
- while Loop
- Loop Condition
- Accumulator Pattern
- Infinite Loop and Termination
Theory
while Loop
What. A while loop repeats a block of code over and over, as long as a condition stays true. Before each pass it re-checks the condition, and the moment the condition is false it stops, runs its else block if it has one, as this lesson's Assignment does, and continues after the loop.
Why. It is the most general form of repetition: it keeps going until something changes, which is exactly what you want when you do not know in advance how many passes are needed, train until loss stops improving, retry until a value is valid.
When. Reach for while when the number of repetitions is unknown and the loop should run until a condition flips, rather than a fixed count.
Nothing needs installing, while is a keyword built into the language. The shape mirrors the if from last lesson: the keyword, a condition, a colon, and an indented block. The one new idea is that the block runs repeatedly, with the condition re-checked before every pass.
# 'epoch' starts at 0, the loop runs while the condition stays True.
epoch = 0
while epoch < 3:
print("training epoch", epoch)
epoch = epoch + 1 # CHANGES the variable so the condition will eventually failThe output is three lines, for epochs 0, 1 and 2, and the loop stops when 3 < 3 turns out false. The critical line is epoch = epoch + 1. Without it epoch would stay 0 forever, the condition would be true at every check, and the loop would never end.
A while loop is closely related to the conditional from Lesson 1.2.1. An if checks a condition once and runs its block at most once. A while checks the same kind of condition but keeps coming back to run the block again until the condition fails, think of it as a branch that loops.
# Compare: an 'if' runs at most ONCE.
ready = True
if ready:
print("checked once")
# A 'while' keeps running the block until the condition turns False.
count = 0
while count < 2:
print("looped", count)
count += 1 # augmented assignment from Lesson 1.1.3The structural difference is repetition alone: the same style of condition, but the loop re-evaluates it and re-runs the block until the test is no longer satisfied.
DON'T:
- DON'T forget to change a variable used in the condition inside the loop, without an update, and with no
break, the loop never stops. - DON'T confuse
whilewithif,ifruns the block at most once,whileruns it repeatedly while the condition holds.
Loop Condition
What. The loop condition is the test checked before each pass of a while loop. If it is true, the body runs once more, if it is false, the loop ends, running its else block first when it has one.
Why. The condition is the loop's contract: it defines precisely when work continues and when it stops. Reasoning about a loop is mostly reasoning about its condition and what changes it.
When. You design a loop condition every time you write a while, it should be true at the start (so the body runs at least once when intended) and become false after the right amount of work.
The condition is checked before the body, never during it. This "check, then run, then check again" order has a consequence: if the condition is false the very first time, the body runs zero times. The loop never enters.
# The condition is False from the start, so the body NEVER runs.
remaining = 0
while remaining > 0:
print("processing") # never prints
remaining -= 1
print("loop skipped") # this prints, the loop body ran zero timesThis is correct and frequently useful behavior rather than an edge case: a while guards its body, and running zero times is the right answer when there is nothing to do.
The condition is re-evaluated using the current values of its variables each pass. So whatever the body changes, the next check sees the updated value. This is the whole mechanism by which a loop eventually stops: the body nudges a variable toward making the condition false.
# The condition watches 'budget', each pass spends some, moving toward False.
budget = 10
while budget >= 3:
print("spend 3, budget was", budget)
budget -= 3 # moves 'budget' down toward failing the condition
print("final budget:", budget)budget takes the values 10, 7 and 4 on the three passes that run, then stops at 1, because 1 >= 3 is false. Note that it does not land on zero, the loop stops when the condition fails rather than when the value is exhausted. The condition and the body's update work as a pair: the condition watches a value, the body moves that value, and eventually the watch fails.
DON'T:
- DON'T assume the body always runs at least once, if the condition starts false, it runs zero times (use a different structure if you need "run once then check").
- DON'T write a condition on a variable the body never changes, it will be true forever or false forever.
Accumulator Pattern
What. The accumulator pattern uses a variable, initialized before the loop, that the loop body updates to carry a result forward, a running total, a running count, a running maximum. Why. It is how a loop produces a single answer from many passes. Nearly every "summarize a collection" task, sum, count, average, max, is an accumulator running over the data. When. Use it whenever you need one cumulative result built up across iterations rather than a separate answer per pass.
The pattern has three fixed parts: initialize the accumulator before the loop (usually to 0, 0.0, or an empty/identity value), update it inside the loop, and use it after the loop ends. The update is the canonical case of rebinding a name from Lesson 1.1.3, read the old value, combine it with the current pass, rebind.
# INITIALIZE the accumulator before the loop.
total_loss = 0.0
batch = 1
while batch <= 3:
batch_loss = 0.25 * batch # a fake per-batch loss
total_loss = total_loss + batch_loss # UPDATE: read old, add, rebind
batch += 1
# USE the accumulated result after the loop.
print("total loss:", total_loss) # total loss: 1.5 (0.25 + 0.5 + 0.75)total_loss reads 0.25, then 0.75, then 1.5 as the passes go by. What makes it an accumulator rather than just a variable is that it carries state across passes, each iteration building on the result of the one before, which is why where you initialize it matters so much.
A counting accumulator is the same idea with += 1, and it pairs naturally with a conditional to count how many values satisfy a test, the loop-plus-if shape you will use constantly when filtering data.
# Two accumulators: a count of passing items and a running sum.
n_passed = 0
running_sum = 0
value = 1
while value <= 5:
running_sum += value # accumulate the sum: 1+2+3+4+5
if value % 2 == 0: # conditional from Lesson 1.2.1
n_passed += 1 # count only the even values
value += 1
# sum: 15 evens: 2
print("sum:", running_sum, "evens:", n_passed)The if is what separates the two accumulators, one updated every pass and one only on the passes that qualify, using the % test from Lesson 1.1.4. This loop-with-accumulators-and-a-condition is the exact shape of "sum this column and count how many rows pass a filter", which is the everyday work of summarizing data.
DON'T:
- DON'T initialize the accumulator inside the loop, it would reset every pass and never accumulate.
- DON'T forget to initialize at all, using a name before it is assigned raises an error.
Infinite Loop and Termination
What. An infinite loop is a while whose body repeats forever, because its condition never becomes false and nothing else ends it, so the program hangs. Termination is the guarantee that a loop will eventually stop, which requires the body to make progress toward failing the condition.
Why. The infinite loop is the first bug you can inflict on yourself that freezes the program rather than crashing it, recognizing and preventing it is essential. Every correct loop must have a clear reason it terminates.
When. Check for termination every single time you write a while: ask "what variable does the condition watch, and what in the body moves it toward making the condition false?"
An infinite loop happens when the condition stays true and nothing ends the loop, most often because the body fails to change the condition's variables, changes them in the wrong direction, or steps past the value that would stop it. The classic cause is forgetting the update line.
# INFINITE LOOP (do NOT run): 'count' never changes, so 'count < 3' stays True forever.
count = 0
while count < 3:
print("looping")
# MISSING: count += 1
# Without an update, the condition is True on every check and the program hangs.Nothing after the loop is ever reached, which is what makes this different from a crash: there is no traceback and no exit, just a program that never comes back. If you run a hanging program by accident, press Ctrl-C in the terminal to interrupt it, which sends a stop signal and returns you to the prompt.
To guarantee termination, a while whose condition compares a value against a limit needs a variant: some quantity that strictly moves toward the condition becoming false on every pass. For a counter, that is incrementing toward an upper bound, for a countdown, decrementing toward zero. Naming this quantity is how you prove the loop stops.
# Correct termination: 'attempts' increases every pass toward the limit.
attempts = 0
max_attempts = 4
while attempts < max_attempts:
print("attempt", attempts)
attempts += 1 # the VARIANT: strictly increases toward max_attempts
print("stopped after", attempts, "attempts")The phrase to internalize, and to be able to say about every such while you ever write, is this: "the condition watches attempts, the body increases attempts, so the loop must stop." If you cannot say that sentence about a loop, you have not shown that it terminates.
DON'T:
- DON'T write a
whilethat compares against a limit without a clear variant, name the variable that moves toward stopping the loop, every time. - DON'T update the variant in the wrong direction, incrementing when the condition needs it to decrease creates an infinite loop.
Additional
If a loop genuinely needs to run until a signal arrives, the usual pattern is a flag, a boolean the body can flip to end the loop: running = True before it, while running:, and running = False inside when the stopping condition is met. A flag is a stop signal rather than a variant, since it holds still until the pass that flips it, and it needs the same kind of proof, something in the body must actually be able to flip it.
Lab Exercises
Both problems first, then both solutions. Do not peek.
Lab Exercise 1: Counting Down, and Not Running At All
Covers the first half (while Loop, Loop Condition).
In a script countdown.py, start n = 5 and write a while loop that prints n each pass and decrements it, stopping when n reaches 0. Confirm it prints 5 4 3 2 1. In a comment, name the variable the condition watches and the exact line that moves it toward stopping.
Then, in the same file, set remaining = 0 and write while remaining > 0: with a body that prints "working" and decrements remaining. After that loop, print "done". Run it and explain in a comment why "working" never prints while "done" does, and why that is the loop behaving correctly rather than failing.
Lab Exercise 2: Two Accumulators, and Proving It Stops
Covers the second half (Accumulator Pattern, Infinite Loop and Termination).
Create sum_count.py. Using a while loop over the values 1 through 10 inclusive, accumulate two results: total, the sum of all ten values, and n_big, the count of values strictly greater than 5. Initialize both accumulators before the loop, update them inside, and print both after. Confirm total is 55 and n_big is 5. Explain in a comment why the accumulators are initialized before the loop and not inside it.
Then add a second loop simulating a loss that halves each epoch. Start loss = 1.0 and epoch = 0, loop while loss > 0.1, and each pass halve the loss, increment epoch, and print both. After the loop, report how many epochs it took. In a final comment, name the variant that guarantees this second loop terminates, and say what would happen if the halving line were removed.
Solution 1: Counting Down, and Not Running At All
n = 5
# The condition watches 'n', and the body's 'n -= 1' is what moves it toward 0.
while n > 0:
print(n)
n -= 1 # 5 4 3 2 1, then n is 0 and 0 > 0 is False
remaining = 0
# Checked BEFORE the first pass, and 0 > 0 is already False.
while remaining > 0:
print("working") # never runs
remaining -= 1
print("done")
# 'working' never prints because the condition is false at the very first check,
# so the body runs zero times. 'done' is after the loop, so it always runs. A
# while that runs zero times is the loop guarding its body, not the loop failing.Run it:
# Count down, then demonstrate the zero-iteration loop.
python3 countdown.pyThe first loop prints 5 4 3 2 1 and stops when n reaches 0, since 0 > 0 is false. The second prints only done.
The zero-iteration case is worth more attention than it usually gets. A loop that ran no passes and a loop that was never written produce identical output, so when a total comes back at its initial value, "the loop did nothing" is a real possibility to check rather than an absurd one.
DON'T:
- DON'T assume a
whilebody always runs at least once, if the condition starts false it runs zero times. - DON'T drop the
n -= 1, the condition watchesnand nothing else would ever change it.
Solution 2: Two Accumulators, and Proving It Stops
# INITIALIZE both accumulators BEFORE the loop, so they survive across passes.
total = 0
n_big = 0
k = 1
while k <= 10:
total += k # updated on every pass
if k > 5: # conditional from Lesson 1.2.1
n_big += 1 # updated ONLY on passes that qualify
k += 1
print("total:", total, "n_big:", n_big) # total: 55 n_big: 5
# Initialized before the loop because an accumulator has to carry its value from
# one pass into the next. Put 'total = 0' inside and every pass would wipe it,
# leaving only the last value at the end.
loss = 1.0
epoch = 0
while loss > 0.1:
loss = loss / 2 # the VARIANT: strictly shrinks toward 0.1
epoch += 1
print("epoch", epoch, "loss", loss)
print("took", epoch, "epochs")
# The variant is 'loss', halved every pass, so it strictly decreases and must
# eventually drop below 0.1. Remove that halving line and 'loss' stays 1.0, the
# condition is true at every check, and the loop runs forever.Run it:
# Accumulate a sum and a filtered count, then converge a loss.
python3 sum_count.pyThe first loop prints total: 55 n_big: 5. total takes every value, n_big only the five values above 5, and the if inside the loop is the only thing separating them.
The second loop prints four epochs, 0.5, 0.25, 0.125 and 0.0625, then stops. Notice it overshoots: the loop cannot stop at exactly 0.1, it stops at the first value that fails the condition, which is 0.0625. A loop ends where its condition breaks, not where you would have liked it to land.
DON'T:
- DON'T initialize an accumulator inside the loop, it would reset every pass and hold only the final value.
- DON'T expect the converging loop to land on
0.1exactly, it stops at the first value below the threshold. - DON'T write a
whilethat compares against a limit without naming its variant, if nothing in the body moves the watched value and nothing else ends the loop, it will not stop.
Theory Assessment
Conceptual reinforcement, not a coding section. All four questions with their hints first, then all four answers.
Q1: When the Condition Is Checked
Two parts on the same mechanism. First, say exactly when a while loop's condition is evaluated relative to its body, and what that ordering implies. Second, say what starting value of remaining makes the body of while remaining > 0: run exactly zero times, and explain why that is correct behavior rather than a bug.
Hint: The check happens before the body, every time, including the very first time. Ask what follows if the very first check already fails.
Q2: The Three Parts, and a Trace
Two parts on the accumulator. First, name the three fixed parts of the accumulator pattern and say where each one goes relative to the loop. Second, trace total pass by pass and give its final value:
total = 0
k = 1
while k <= 4:
total = total + k
k += 1Hint: Initialize, update, use, which is one before, one inside and one after. For the trace, add each k to the running total one pass at a time and write down all four intermediate values.
Q3: Why It Stops, and Why This One Does Not
Two parts on termination. First, explain what has to be true for a while loop to terminate, and what a variant is. Second, say why the loop below never ends, and give the smallest fix:
count = 0
while count < 3:
print("looping")Hint: Something in the body must move a variable the condition watches, in the direction that eventually makes the condition false. For the second part, look for what the condition watches and ask what changes it.
Q4: The Bug That Hangs and the Bug That Lies
Here are two attempts to sum the values 1 through 4. Neither prints 10.
# Attempt A
value = 1
while value <= 4:
total = 0
total = total + value
value += 1
print(total)# Attempt B
value = 1
total = 0
while value <= 4:
total = total + value
print(total)Answer three things. First, say exactly what Attempt A prints and why that specific number. Second, say what Attempt B does. Third, and this is the point of the question: one of these two is far more dangerous in real work than the other. Say which, and justify it in terms of how each one announces itself, not in terms of which is harder to write.
Hint: For A, ask what the accumulator's value is at the top of each pass. For the third part, imagine both scripts running unattended overnight in a pipeline, and ask what you would find in the morning in each case.
Answer 1:
The condition is evaluated before the body, every time, including the very first time, and never during the body. So the order is check, run, check, run, and the loop exits, through its else block when it has one, the moment a check fails. The implication is that the body runs zero times whenever the condition is already false on entry, since there is no path that runs the body before the first check.
Start remaining at 0 (or any value not greater than zero), so that the first check of remaining > 0 is 0 > 0, which is false. That is correct behavior rather than a bug, because a while is a guard as well as a repeater. Zero passes is the right answer when there is no work to do, and demanding at least one pass would require a different structure.
DON'T assume a while body always runs at least once, that is a guarantee while does not make.
Answer 2:
The three parts are initialize the accumulator before the loop, update it inside the loop, and use it after the loop ends. The positions are the pattern: one before, one inside, one after, and moving any of them breaks it.
The trace runs total through 1, then 3, then 6, then 10, as k takes the values 1, 2, 3 and 4. The final value is 10. Each pass reads the old total, adds the current k, and rebinds total, which is exactly the read-then-rebind order from Lesson 1.1.3.
DON'T initialize the accumulator inside the loop, it would reset every pass and never accumulate anything.
Answer 3:
A while terminates when the body makes progress toward falsifying its own condition. The formal name for that progress is a variant: some quantity that strictly moves in one direction on every pass, toward the value that makes the condition false. Naming the variant is how you show a loop that compares against a limit stops, and one whose variant you cannot name has not been shown to terminate.
The loop below never ends because the condition watches count and nothing in the body changes count, so count < 3 is 0 < 3 on every check, forever. The smallest fix is to add count += 1 inside the body, which supplies the missing variant and makes the loop run three times.
DON'T write a condition on a variable the body never touches, it can only be true forever or false forever.
Answer 4:
Attempt A prints 4. total = 0 sits inside the loop, so it is reset at the top of every pass. Each pass therefore computes 0 + value and throws away everything earlier, and the last pass runs with value equal to 4. What gets printed is not a total at all, it is simply the final value, and it happens to look like a plausible number.
Attempt B never prints anything. value is never incremented, so value <= 4 stays true forever, the loop spins, and the print after it is never reached. The program hangs until it is killed.
Attempt A is far more dangerous, and the reason is how each one announces itself. B fails loudly and immediately, in the most obvious way a program can fail: it stops responding, nothing is produced, and anyone watching notices within seconds. A fails silently. It terminates normally, it prints a number, the number is the right type and the right order of magnitude, and the process exits cleanly, so every automatic check that a script "worked" reports success. Run both unattended overnight and B is found hung in the morning with no output, while A has finished, written 4 into a report, and moved on. The bug that hangs costs you an hour, the bug that lies can go unnoticed for as long as nobody independently knows what the answer should have been.
DON'T treat a clean exit and a plausible number as evidence of correctness. And DON'T rank bugs by how hard they are to write, rank them by how loudly they fail, because a silent wrong answer outlives a loud one.
Assignment
One assignment. The problem and its hints first, then the solution.
Assignment: Simulated Training Loop
Create train_loop.py, simulating training until convergence with a safety cap. Start loss = 2.0, epoch = 0 and max_epochs = 20.
Loop while loss > 0.05 and epoch < max_epochs, a compound condition from Lesson 1.2.1. Each pass: multiply loss by 0.7, increment epoch, accumulate total_loss as the sum of the losses seen, and print the epoch and the loss. After the loop, print the final epoch and the average loss, total_loss / epoch. Use a while-else clause to report "converged" only when the loop ended because of the loss condition rather than the epoch cap.
In comments, settle three things: name both parts of the variant, explain why the cap epoch < max_epochs guarantees termination even if the loss never converged, and say what total_loss / epoch would do if the loop had run zero passes and why the given starting values mean it cannot.
Hints:
- The loop has two stopping conditions joined by
and, and either one turning false ends it, so name a variant for each:lossshrinking toward the threshold,epochgrowing toward the cap. - The
while-elseclause runs on normal completion, so inside it check whetherloss <= 0.05to tell a real convergence apart from having hit the cap.
Solution:
loss = 2.0
epoch = 0
max_epochs = 20
total_loss = 0.0
# Compound condition: stop when the loss is low enough OR the cap is reached.
while loss > 0.05 and epoch < max_epochs:
loss = loss * 0.7 # variant part 1: loss shrinks toward 0
epoch += 1 # variant part 2: epoch climbs toward the cap
total_loss += loss # accumulate the losses seen
print("epoch", epoch, "loss", round(loss, 4))
else:
# while-else runs on normal completion, when the condition became False.
if loss <= 0.05:
print("converged")
else:
print("hit epoch cap without converging")
print("final epoch:", epoch, "avg loss:", round(total_loss / epoch, 4))
# The variant has TWO parts: loss * 0.7 drives loss down, epoch += 1 drives epoch
# up. Either reaching its limit ends the loop.
# The cap is what GUARANTEES termination. The loss condition alone is a promise
# about the data, and if the decay were ever 1.0 the loss would never fall, but
# epoch strictly increases to max_epochs no matter what the loss does.
# 'total_loss / epoch' would raise ZeroDivisionError on zero passes, since epoch
# would still be 0. It cannot happen here because loss starts at 2.0 and epoch at
# 0, so both parts of the condition are true at the first check and at least one
# pass always runs.Run it:
# Run the capped training loop.
python3 train_loop.pyThe loss decays from 2.0 by a factor of 0.7 each pass and crosses below 0.05 at epoch 11, where it reaches 0.0395. The loop therefore stops on the loss condition rather than the cap, the else clause prints converged, and the final line reports final epoch: 11 avg loss: 0.4159. Both exits here are normal completions, so the else runs every time and only groups the report, Lesson 1.2.4 shows the exit it was built to tell apart.
The cap earns its place precisely because it does nothing here. epoch < max_epochs never fired, and that is what makes it a safety net rather than part of the logic: it costs one comparison per pass and converts a loop that terminates if the data behaves into one that terminates unconditionally. The two variants are independent, and only one of them is under your control, which is the argument for always writing the one that is.
DON'T rely on the loss condition alone for termination, a decay that stalled would loop forever. And DON'T divide by an accumulator-driven counter without knowing it cannot be zero, here the starting values guarantee at least one pass, and that guarantee is the thing being relied on.
Additional Resources
Optional, and nothing that follows depends on either one. Worth opening only if this lesson raised a question it did not answer.
- YouTube - "Learn Python - Full Course for Beginners [Tutorial]" by freeCodeCamp.org. The segment on
whileloops, for a second visual pass over conditions and termination. - Official docs - The Python Tutorial, "else Clauses on Loops". The full account of the
while-elseclause the assignment used.
Summary
This lesson added repetition to the decisions the last one taught. The while loop is deceptively simple, check a condition, run a block, check again, but that small cycle is enough to express any repeated work whose length you do not know in advance. The whole art of writing one well comes down to two questions you must be able to answer before you run it: what condition keeps it going, and what in the body moves that condition toward false? A loop you cannot answer the second question about is a loop that may never stop, and the infinite loop is the first bug that hangs your program instead of crashing it loudly.
The accumulator pattern is where loops start producing real answers. A single variable, set up before the loop and nudged forward as the passes go by, is how many iterations collapse into one result, a sum, a count, a maximum, an average. It is nothing more than the rebinding you learned with variables, now happening in a rhythm, and it pairs with the conditionals from the last lesson to count and filter at the same time. Initialize outside, update inside, use after: that three-beat structure will become so automatic you stop seeing it as a pattern at all.
None of this looks like data science yet, but it is the engine underneath all of it. Summing a column, counting how many rows pass a filter, averaging a feature, tracking the best score across training epochs, every one of these is an accumulator running over your data, terminated by a condition you reasoned about in advance. The while loop you learned here is the most general form of that engine. The next lesson introduces the for loop, which trades some of that generality for a cleaner shape when you already know exactly what you are looping over, which, with data, is most of the time.
Cheat Sheet
Part A - Reference Table
| Concept | Syntax / shape | What it does | When to avoid |
|---|---|---|---|
while loop |
while cond: + indented body |
Repeats body while condition is true | When the count is known (use for) |
| Loop condition | the condition after while |
Checked before every pass | Watching a variable the body never changes |
| Accumulator | acc = 0 before, acc += x inside |
Carries a running result across passes | Initializing inside the loop |
| Variant | the variable that moves toward false | Guarantees termination | Omitting it from a limit check → infinite loop |
| Infinite loop | condition never becomes false, nothing else ends it | Program hangs (use Ctrl-C) |
Forgetting the update line |
| Flag control | running = True / while running: |
Stops when a boolean is flipped | Never flipping the flag |
Part B - Compact Code Block
i = 0
while i < 5: # condition checked BEFORE each pass
print(i)
i += 1 # variant: moves toward stopping the loop
total = 0 # initialize accumulator OUTSIDE the loop
n = 1
while n <= 10:
total += n # update accumulator each pass
n += 1
print(total) # 55, the accumulator read AFTER the loop
# never-updated condition loops forever, Ctrl-C stops it
running = True # flag-controlled loop
while running:
running = False # body flips the flag to terminate