while

The condition is re-checked before every pass. Nothing changes it for you — if the body never makes it false (or breaks), the loop runs forever.

Control flowPython 3 (all)Live demo
while
while condition:
    body
while / else
while condition:
    body      # may break
else:
    no_break  # condition went false
while True + break
while True:
    step
    if done:
        break
Use for
while n > 0: / while True: … break / while queue:
Result
a statement — no value; runs 0 or more times
Pairs with
break, continue, else, if
Watch out
update the loop variable on every path; use for when you loop over items

Demo

Live evaluation
Halve a number until it reaches 0. The condition is checked before every pass — a start at 0 or below never enters the loop.
Try:
Inputs
ninta whole number
Code
n = 100
steps = []
while n > 0:
    steps.append(n)
    n //= 2
steps
Result
[100, 50, 25, 12, 6, 3, 1]

In the while tab, 0 and negative numbers give an empty list: the test n > 0 is false before the first pass, so the body never runs. In the while / else tab, 0 and 5 never match an attempt, the condition attempts < 3 goes false, and else runs; any break jumps past it. In the while True tab, the loop only ends at "stop" — with no stop item, the loop keeps popping until the list is empty and pop raises IndexError, which is how an unguarded while True fails when the exit never comes.

Syntax slots

NameTypeRequiredDescription
conditionexpressionyesEvaluated before each iteration, truthiness rules as in if. False on the first check → the body never runs.
bodyblockyesMust eventually make the condition false, or leave with break / return / an exception.
elseblocknoRuns once when the condition turns false — skipped if the loop was left with break.

Common patterns

Process until empty
A non-empty list / deque is truthy, so while queue: stops when it is drained.
from collections import deque

def drain(queue: deque):
    while queue:
        item = queue.popleft()
        print(item)
Loop and a half
Python has no do-while; while True with a break in the middle runs the first step unconditionally.
def read_chunks(f, size=4096):
    while True:
        chunk = f.read(size)
        if not chunk:
            break
        yield chunk
Walrus in the condition (3.8+)
Assign and test in one step instead of repeating the call before and inside the loop.
def read_chunks(f, size=4096):
    while (chunk := f.read(size)):
        yield chunk
Bounded retry with while / else
else handles "all attempts failed" without a flag variable.
def fetch(try_once, attempts=3):
    while attempts > 0:
        attempts -= 1
        if (result := try_once()) is not None:
            break
    else:
        raise TimeoutError("no result")
    return result

Examples

1. Count down
n = 3 while n > 0: print(n) n -= 1
Returns
3 2 1
2. False at the start → 0 passes
n = 0 while n > 0: print('never') n
Returns
0
3. Digits of a number
n = 4096 digits = 0 while n: n //= 10 digits += 1 digits
Returns
4
4. Drain a list (non-empty is truthy)
stack = [1, 2, 3] while stack: print(stack.pop())
Returns
3 2 1
5. while True with break
n = 1 while True: n *= 2 if n > 50: break n
Returns
64
6. else runs when the condition goes false
i = 0 while i < 2: i += 1 else: print('done at', i)
Returns
done at 2
7. break skips else
i = 0 while i < 5: i += 1 if i == 2: break else: print('not printed') i
Returns
2

Pitfalls

1. Off-by-one with <= len()
Valid indexes stop at len - 1. <= walks one step past the end.
i <= len(items)
items = ['a', 'b', 'c']
i = 0
while i <= len(items):
    print(items[i])
    i += 1
a b c IndexError: list index out of range
i < len(items)
items = ['a', 'b', 'c']
i = 0
while i < len(items):
    print(items[i])
    i += 1
a b c
2. An exact float test that never becomes true
0.1 is not exact in binary, so adding it ten times gives 0.9999999999999999, and x != 1.0 stays true forever. (A safety cap is added here so the snippet ends.) Count with an integer instead.
x != 1.0
x = 0.0
steps = 0
while x != 1.0:
    x += 0.1
    steps += 1
    if steps == 50:  # safety cap
        break
(steps, x)
(50, 4.999999999999998)
integer counter
steps = 0
while steps < 10:
    steps += 1
    x = steps / 10
(steps, x)
(10, 1.0)
3. continue before the update
continue jumps straight back to the condition, skipping everything below it — including the increment. (Capped here; without the cap it never ends.)
increment at the bottom
i = 0
seen = []
passes = 0
while i < 4:
    passes += 1
    if passes > 10:  # safety cap
        break
    if i == 2:
        continue
    seen.append(i)
    i += 1
(seen, i)
([0, 1], 2)
increment first
i = 0
seen = []
while i < 4:
    i += 1
    if i == 2:
        continue
    seen.append(i)
seen
[1, 3, 4]
4. while over indexes instead of for
A manual index is extra state to get wrong. When you walk a collection, for does the counting.
manual index
names = ['Ann', 'Bo']
i = 0
out = []
while i < len(names):
    out.append(names[i].upper())
    i += 1
out
['ANN', 'BO']
for loop
names = ['Ann', 'Bo']
out = []
for name in names:
    out.append(name.upper())
out
['ANN', 'BO']

When to use

Use it
  • Repeating until a condition changes — input is valid, a queue is empty, a value converges
  • Loops where the number of passes is not known in advance
  • Event / retry loops written as while True with break
Reach for something else
  • Walking the items of a list, string, dict or file → for
  • Counting a fixed number of times → for i in range(n)
  • Waiting for time to pass in a busy loop → time.sleep or an event

Notes

CPython impl
The condition is re-evaluated at the top of every pass; while True is compiled without any test at all
do-while
Python has no do-while; while True: … if not cond: break runs the body at least once
Interrupt
A runaway loop in a terminal is stopped with Ctrl+C, which raises KeyboardInterrupt inside it

FAQ

In code: give it an exit — a condition that the body eventually makes false, or a break. At the terminal: Ctrl+C raises KeyboardInterrupt and ends the program (unless the loop catches it with a bare except, which is one more reason not to write those).