A loop repeats a block of code. Normally, Python checks a condition first — if the condition is false, the code inside never runs at all. A do while loop flips that order: the code runs first, then Python checks whether to run it again. This means the code always executes at least once, no matter what. Python has no do while keyword, but you get the exact same behavior with while True: and a break statement at the end. In this tutorial you'll learn how that works, why the position of break is the key, and when to use this pattern in python programming.
Start with the pattern itself. You will see it used in input validation, retry logic, menu-driven programs, and anywhere else where the code needs to run at least once before there is anything to check. The sections below build from the basic pattern up to those real-world cases, then cover the edge cases — continue, the walrus operator, try/except, and async — that come up once you start using it regularly.
What a Do While Loop Does
In languages that have native do while syntax, the construct looks roughly like this in pseudocode:
do:
# body always runs at least once
while condition
The body executes unconditionally on the first pass. After that, the condition is evaluated. If it is still true, the loop repeats. If it is false, execution moves on. The key guarantee is that the body runs at least once — regardless of whether the condition would have been true from the start.
A standard while loop does not offer that guarantee. If the condition is false before the first iteration, the body is skipped entirely. Whether that matters depends on what the loop is doing, but for tasks like prompting a user for input, you always need at least one prompt to happen.
The difference between while and do while is purely about when the condition is evaluated: before the body in a standard while loop, after the body in a do while loop.
true?
body may run zero times
if condition starts false
always runs first
condition?
body always runs at least once
condition checked after
The Python Equivalent: while True with break
The canonical Python pattern is straightforward. Open with while True:, write the body, then check the exit condition at the end and call break when it is met.
while True:
# body — runs at least once
if exit_condition:
break
Because True never evaluates to false, the loop will keep running until a break is reached. Placing the break at the end of the block — inside an if — is what makes this behave like a do while: the body completes before the condition is ever checked.
while True?Creates an infinite loop. Because True is a constant in Python 3, this condition never becomes false on its own — the loop runs until a break is reached.:
# body — runs at least once
do_work()
if exit_condition?The exit check lives at the END of the body. This placement is the key — it means the body above always completes before this line is ever reached.:
break?Immediately exits the enclosing while loop. No further iterations run. Because this is inside an if at the bottom of the body, it only fires after the body completes — giving you the do-while guarantee.
Side-by-side comparison
Here is how the same logic reads in JavaScript's native do while versus Python's equivalent:
// JavaScript
let number;
do {
number = parseInt(prompt("Enter a positive number: "));
} while (number <= 0);
# Python equivalent
while True:
number = int(input("Enter a positive number: "))
if number > 0:
break
Both versions guarantee the prompt appears at least once. The Python version is slightly more explicit about when it stops — you can read the exit condition directly as an English sentence: "if number is greater than zero, stop."
Add a short error message before the break check when validating input. Users benefit from knowing what went wrong, not just being prompted again silently.
Real-World Use Cases
Three situations come up repeatedly where the do while pattern is the natural fit.
Input validation
You need at least one prompt to display before you can know whether the input is valid. A standard while loop would require you to call input() before the loop and again inside it — duplicating code. The while True pattern avoids that.
while True:
age = input("Enter your age: ").strip()
if age.isdecimal() and int(age) > 0:
break
print("Please enter a valid positive number.")
age = int(age)
print(f"Age recorded: {age}")
Retry logic
Network requests, file reads, and external API calls sometimes fail. A do while pattern lets you attempt the operation first, then decide whether to retry based on the result.
import time
MAX_RETRIES = 3
attempts = 0
while True:
attempts += 1
success = try_connect() # returns True on success
if success or attempts >= MAX_RETRIES:
break
print(f"Attempt {attempts} failed. Retrying...")
time.sleep(1)
Menu-driven programs
A CLI menu must display at least once before the user can make a selection. The loop runs, shows the menu, reads the choice, and exits when the user selects quit.
while True:
print("\n1. View report")
print("2. Export data")
print("3. Quit")
choice = input("Select an option: ").strip()
if choice == "1":
view_report()
elif choice == "2":
export_data()
elif choice == "3":
break
else:
print("Invalid selection.")
Producer-consumer handshake loops
When one component generates data and another consumes it, you often need to perform at least one read before you have enough state to decide whether the pipeline should continue. A while True loop structures this cleanly without priming the pump outside the loop.
import queue
from collections.abc import Callable
from typing import Any
def drain_queue(q: queue.Queue[Any], processor: Callable[[Any], None]) -> None:
"""Read from q at least once, stop when sentinel None is received."""
while True:
item = q.get() # blocks until an item is available
if item is None: # sentinel value signals end of stream
q.task_done()
break
processor(item)
q.task_done()
The key here is that q.get() blocks. A standard while not q.empty() check would race — the queue might appear empty before the producer places the first item. The do while pattern sidesteps this entirely: the read happens unconditionally, and the sentinel determines exit. This pattern appears in many thread-safe worker implementations, including Python's own concurrent.futures thread pool internals.
State machine step execution
State machines require at least one transition before they can report a result. A do while pattern lets each step run and then evaluate whether the machine has reached a terminal state — without needing to know the initial state before entering the loop.
TERMINAL_STATES = {"done", "error", "timeout"}
state = "init"
while True:
state = transition(state) # always execute at least one step
log_transition(state)
if state in TERMINAL_STATES:
break
This is meaningfully different from placing the terminal-state check before transition(). If "init" happened to be in TERMINAL_STATES due to a misconfiguration, a pre-check loop would exit immediately with no transitions logged. The do while form guarantees one transition always fires, which is often the correct contract for a state machine — you must move at least once before declaring done.
Buffered I/O and chunk reading
Reading a file or socket in fixed-size chunks requires reading first, then deciding whether there is more data. Placing the read inside a standard while loop requires reading outside the loop to prime the condition, which duplicates the call. The do while pattern eliminates that duplication.
import hashlib
CHUNK_SIZE = 65536 # 64 KiB
def hash_file(path: str) -> str:
digest = hashlib.sha256()
with open(path, "rb") as f:
while True:
chunk = f.read(CHUNK_SIZE)
if not chunk:
break
digest.update(chunk)
return digest.hexdigest()
Compare this with the primed-loop alternative, which duplicates the read call:
# Primed loop — the read call appears twice
with open(path, "rb") as f:
chunk = f.read(CHUNK_SIZE) # duplicated read before the loop
while chunk:
digest.update(chunk)
chunk = f.read(CHUNK_SIZE) # and again inside
The while True version keeps the read in one place. If you later change CHUNK_SIZE or swap f.read for a different source, you update one line instead of two. This is exactly the class of maintenance problem that the do while pattern was designed to prevent.
Exponential backoff with jitter
A retry counter loop is the most commonly shown example, but it underrepresents how the pattern is used in production. A more realistic variant combines the do while guarantee of at least one attempt with exponential backoff and randomized jitter — the approach recommended in distributed systems design to prevent thundering herd problems when many clients retry simultaneously.
import time
import random
def fetch_with_backoff(url: str, max_attempts: int = 5) -> bytes:
base_delay = 0.5 # seconds
cap_delay = 30.0 # never wait longer than this
attempts = 0
last_exc = None
while True:
attempts += 1
try:
return http_get(url) # attempt always runs first
except TransientError as exc:
last_exc = exc
if attempts >= max_attempts:
break
# Full jitter: random value in [0, min(cap, base * 2^attempt)]
ceiling = min(cap_delay, base_delay * (2 ** attempts))
delay = random.uniform(0, ceiling)
time.sleep(delay)
raise last_exc
The do while guarantee matters here because the attempt always fires before any backoff delay is calculated and before the attempt counter is compared against the maximum. A while attempts < max_attempts guard at the top would require initializing attempts to the right value before the loop and would obscure the intent. The while True form reads directly as: try, then decide.
Converging numerical iteration
Algorithms that converge on a solution — Newton's method, gradient descent, fixed-point iteration — must run at least one step before they have a residual to test. The exit condition is the convergence criterion, and it cannot be evaluated until after the first iteration produces an updated estimate.
def newton_sqrt(n: float, tolerance: float = 1e-10) -> float:
"""Approximate the square root of n using Newton's method.
n must be a positive, non-zero float. Negative values or zero
will raise ZeroDivisionError or produce incorrect results.
"""
x = n / 2.0 # initial guess
while True:
x_next = 0.5 * (x + n / x) # one Newton step
if abs(x_next - x) < tolerance: # convergence test after the step
return x_next
x = x_next
There is no meaningful tolerance test before the first step — x and x_next do not both exist until the body runs. This is a structural do while requirement: the exit condition depends on values that are only produced by the body, so a pre-check loop cannot even be formed without introducing a sentinel or dummy initial value. The while True pattern makes this dependency explicit in the code layout.
Why Python Never Added Do While
PEP 315 was originally authored by W. Isaac Carroll and later picked up by Raymond Hettinger. Created on April 25, 2003, it proposed an optional do clause at the beginning of the while loop so that setup code could run at least once before the condition was evaluated. The proposal was deferred in February 2006. Revival attempts in April 2009 failed to produce any syntax that could compete with the existing while True / if / break form.
What is rarely mentioned is that the 2013 rejection thread was triggered by Łukasz Langa, who posted to python-ideas acknowledging that while True: was "good enough" and proposing that the PEP be summarized and closed. Langa also sketched two alternative forms that had not been formally considered: a do: block with the if condition: break still inside, and a bare while: with an empty predicate. The empty-predicate variant would have allowed Python's parser to verify that a break actually existed in the body. Neither gained traction. On June 26, 2013, Guido van Rossum replied directly:
"Please reject the PEP. More variations along these lines won't make the language more elegant or easier to learn. They'd just save a few hasty folks some typing while making others who have to read/maintain their code wonder what it means."
— Guido van Rossum, python-ideas mailing list, June 26, 2013
Guido's full message explained that more syntax variations of this kind would not make Python more elegant or easier to learn, and that the while True with break form was already good enough. The PEP was officially closed that day.
The full python-ideas thread also reveals a nuance that most summaries omit: multiple community members noted that the while True: form is actually more expressive than a native do while, because the break can be placed anywhere in the body — not only at the bottom. This means you can exit mid-body on an exceptional condition, something a traditional do while cannot represent cleanly. Guido's rejection leaned on exactly this point: the existing idiom is a strict superset of what any do while keyword could offer.
PEP 315 is permanently rejected. The Python documentation and the PEP itself explicitly direct users to use while True: with an inner if / break whenever a do while loop would be appropriate. This is not a workaround — it is the officially sanctioned idiom.
The while 1 vs while True distinction
Before Python 2.2, True was not a built-in name at all — it was simply undefined, and early Python code used the integer 1 as a stand-in for boolean true. Python 2.2 added True and False as built-in names, but they were still ordinary names that user code could reassign. That reassignability meant while 1: remained the more reliable choice in safety-conscious code of that era — the integer literal 1 is always truthy and cannot be shadowed by user code under any circumstances. Python 3 resolved the ambiguity entirely by making True and False reserved keywords that cannot be reassigned at all (Python 3 Language Reference — Keywords). In any Python 3 codebase, both forms are equivalent — but you will still encounter while 1: in older code, C-extension authors' style guides, and codebases originally written for Python 2. It is not wrong, just dated.
# Older style — still valid, but prefer while True in modern Python
while 1:
response = input("Enter something: ").strip()
if response:
break
# Modern style — clearer intent
while True:
response = input("Enter something: ").strip()
if response:
break
How continue behaves in the pattern
One behavior that catches people coming from other languages: continue inside a while True loop jumps back to the top of the loop — back to the while True: line — not to the break check. This means any code between the continue and the if / break will be skipped. If your exit condition check lives at the bottom and a continue is above it, the loop will keep iterating without ever reaching the exit check on that particular pass. This is usually intentional, but it requires care.
while True:
line = input("Enter a number (blank to finish): ").strip()
if not line.isdecimal():
print("Numbers only — try again.")
continue # jumps back to while True:
# the break below is NOT reached on this pass
number = int(line)
process(number)
if number == 0:
break # only reachable when input is a valid decimal digit string
At the CPython bytecode level, while True: compiles to an unconditional backward jump — the interpreter never evaluates a condition at the top. break compiles to a forward jump out of the loop. There is no hidden overhead from the True literal; the peephole optimizer removes any conditional test entirely. The specific instruction name changed across versions: Python 3.10 and earlier used JUMP_ABSOLUTE; Python 3.11 replaced it with JUMP_BACKWARD as part of the adaptive specializing interpreter (PEP 659). In both cases the semantic effect is identical — an unconditional loop.
What about the walrus operator?
Python 3.8 introduced the walrus operator (:=, PEP 572), which assigns a value inside an expression. In some cases it reduces the need for while True by letting you assign and test in a single condition line. Compare these two approaches for reading lines until an empty string:
# Classic while True pattern (works in all Python versions)
while True:
line = input("Enter text (blank to quit): ").strip()
if not line:
break
print(f"You entered: {line}")
# Walrus operator form (Python 3.8+)
while line := input("Enter text (blank to quit): ").strip():
print(f"You entered: {line}")
The walrus version is more concise, but it still prints the prompt before evaluating the condition — the body runs only when the condition is truthy. This is not truly equivalent to a do while pattern because the condition is checked first. For cases where the body must run unconditionally on the first pass regardless of any condition, while True with break remains the correct tool. The walrus operator solves a different class of problem: eliminating the duplication of a variable assignment that also serves as a loop condition.
Does the else clause work with while True?
Python's while loop supports an else clause. The else block runs when the loop exits because its condition became false — but it does not run when the loop exits via break. This distinction is directly relevant to the do while pattern.
Because while True: never becomes false on its own, the else clause under while True: is unreachable. The loop can only exit through break, which always suppresses the else. Writing an else block there is syntactically valid but logically dead code. The practical use of while/else is in bounded loops where exhausting all iterations without breaking is a meaningful outcome — such as an attempt counter.
# while True: the else block is dead code — break always suppresses it
while True:
response = input("Enter a command: ").strip()
if response == "quit":
break
else:
print("Loop ended naturally") # never executes
# Standard while: else IS useful here
attempts = 0
while attempts < 3:
attempts += 1
if try_connect():
break
else:
# Only runs if the loop exhausted all attempts without a break
print("All attempts failed — no connection established")
If you need both the do while guarantee (at least one attempt) and an "exhausted all retries" outcome, combine both patterns: use a bounded counter inside a while True: loop and handle the exhausted case explicitly at the bottom with an if attempts >= MAX: raise ... rather than relying on while/else.
How does try/except interact with break inside the pattern?
Placing a try/except block inside a while True: loop is common — especially in retry logic and I/O reading — but the interaction between exception handling and break has one subtlety worth knowing: a break inside a try block works exactly as expected. Python does not execute the finally clause and then continue the loop; it runs finally and then exits the loop. The break is honored.
while True:
try:
data = fetch()
if not data:
break # break exits the loop; finally still runs
process(data)
except TransientError:
print("Transient error — retrying")
continue # restart the loop body without reaching break
except FatalError:
raise # re-raise; loop does not continue
finally:
log_attempt() # runs on every iteration, including the one with break
The do while guarantee holds across all paths that reach break: the body — including finally — always executes before the loop exits. The only case where the do while guarantee might appear to break down is if an exception propagates out of the loop entirely before break is reached, which is correct behavior — the loop did not exit via the intended exit condition.
How does while True work in async Python?
In asynchronous Python (asyncio), the while True: with break pattern works exactly the same way structurally. The key difference is that the loop body can now contain await expressions, which yield control back to the event loop while waiting — allowing other coroutines to run concurrently during the wait.
import asyncio
async def poll_until_ready(resource) -> None:
"""Poll a resource at least once, then continue until it reports ready."""
while True:
status = await resource.check_status() # yields control; other tasks run here
if status == "ready":
break
await asyncio.sleep(1.0) # non-blocking delay between polls
async def listen_for_messages(websocket) -> None:
"""Read messages from a websocket until the connection closes.
Uses a None sentinel to signal end-of-stream. Real-world websocket
libraries (e.g. websockets) raise ConnectionClosed instead — wrap
the recv() call in try/except for production use.
"""
while True:
message = await websocket.recv() # yields control until a message arrives
if message is None: # sentinel: None signals end of stream
break
await handle_message(message)
The do while semantics are preserved: check_status() and websocket.recv() each run at least once before the exit condition is evaluated. The await keyword does not change when the condition is checked — it only suspends the coroutine for the duration of the awaited operation. One caution specific to async: a while True: loop with no await inside it will block the entire event loop, because it never yields control. Always include at least one await in an async infinite loop body.
In asyncio servers and WebSocket handlers, while True: with an awaited read is the canonical way to maintain a persistent connection loop. The loop runs at least once — establishing the first read — and exits when the connection closes or a sentinel value is received.
Build the correct Python do while pattern. Arrange the tokens so the loop body runs first and exits when done is True.
while True:, runs the body (do_work()), then checks the exit condition with if done: and calls break last.
You understand the pattern. Now reason about what happens when you change one thing. Each question shows a working while True pattern and asks what a specific mutation would produce.
How to Write a Do While Loop in Python
The structure is always the same three parts: open the loop, write the body, check the exit condition at the end.
-
Open the loop with
while True:Write
while True:to start the loop. BecauseTrueis a constant, the loop will run indefinitely until abreakstatement is reached. The body below it will execute on the very first iteration without any condition check. -
Write the loop body
Place all the code that must run at least once inside the indented block. This is the equivalent of the
do { }block in other languages. It executes without restriction on the first pass. -
Add the exit condition with
if/breakAt the end of the loop body, add an
ifstatement that tests your exit condition. When the condition is met, callbreakto exit the loop. Placing this at the end is what guarantees the body completes at least one full iteration before the exit is evaluated.
This loop is supposed to keep prompting the user until they enter a non-empty string. It has one bug. Which line is wrong?
while False: to while True:. while False means the loop condition is already false before it starts, so the body never executes at all — the exact opposite of the do while pattern.
Enter your name as you want it to appear on your certificate, then start the exam. Your name is used only to generate your certificate and is never transmitted or stored anywhere.
Key Takeaways
- Python has no do while keyword. PEP 315 (originally authored by W. Isaac Carroll, later taken over by Raymond Hettinger) proposed one in 2003. Guido van Rossum formally rejected it on June 26, 2013. The
while Truewithbreakpattern is the officially endorsed alternative. - The pattern guarantees at least one iteration. Because
Trueis always truthy, the loop body executes unconditionally on the first pass before any condition is checked. - Place the break at the end of the body. That placement is what makes the pattern behave like a do while rather than a standard while loop. Code above the
breakalways runs on the first iteration. - Make sure the exit condition is always reachable. Every code path inside the loop should eventually lead to the
break. If no path does, the loop runs forever. continuebypasses the exit check. Acontinuestatement jumps back towhile True:, skipping everything below it — including theif/breakat the bottom. This is usually intentional but requires care when the exit condition lives at the end of the body.while 1:is equivalent but dated. Before Python 2.3,Truewas reassignable, sowhile 1:was the safer idiom. In Python 3 they compile to the same bytecode. Usewhile True:in new code.- The walrus operator is not a do while replacement. The
:=operator (Python 3.8+, PEP 572) assigns and tests in one expression, which reduces duplication in some loops — but it still checks the condition before running the body. Use it when the assigned value naturally serves as the loop condition; usewhile Truewhen unconditional first execution is the requirement.
The while True / break pattern is one of the idioms Python developers recognize immediately. It is not a workaround — it is the intended tool for situations where you need at least one guaranteed iteration before deciding whether to continue.
Frequently Asked Questions
No. Python has no do while keyword. The standard approach is to use while True: with a break statement inside an if block. This guarantees the loop body runs at least once before the condition is checked, which is exactly what a do while loop does in other languages.
PEP 315, proposed in 2003, attempted to add do while syntax to Python. Guido van Rossum rejected it because no proposed syntax felt elegant or consistent with Python's design philosophy. He endorsed the while True with break form as a more general and readable alternative.
The standard equivalent is while True: followed by your loop body, then if condition: break. This pattern runs the body at least once and exits when the condition is met, matching do while behavior exactly.
The break statement goes at the end of the loop body, inside an if block that checks the exit condition. Placing it at the end ensures the body always executes fully at least once before the condition is evaluated.
Yes. The while True loop continues repeating the body until the break condition is met. If the exit condition is not satisfied on the first pass, the loop runs again. It only terminates when the if condition evaluates to True and break is reached.
Input validation is the classic example. You need to prompt the user at least once, then keep prompting until valid input is received. Other common uses include retry logic, menu-driven programs, and processing data in batches until a dataset is exhausted.
Not when used deliberately. while True with a clear break condition is idiomatic Python and is explicitly endorsed by Guido van Rossum and PEP 315. The risk is an accidental infinite loop if the break is never reached, so always make sure the exit condition is reachable.
A standard while loop checks its condition before the first iteration, so the body may never run if the condition is false from the start. A do while loop checks the condition after the first iteration, guaranteeing the body runs at least once regardless of the initial condition.
Always ensure that some code path inside the loop will eventually reach the break statement. Every execution branch that does not break must modify state in a way that moves toward the exit condition. If no such path exists, the loop will run forever.
PEP 315 was originally written by W. Isaac Carroll and later taken over by Raymond Hettinger. Created on April 25, 2003, it proposed an optional do clause for the while statement. The PEP was deferred in February 2006, saw revival attempts in April 2009, and was formally rejected on June 26, 2013, when Guido van Rossum replied on the python-ideas mailing list: "Please reject the PEP. More variations along these lines won't make the language more elegant or easier to learn. They'd just save a few hasty folks some typing while making others who have to read/maintain their code wonder what it means."
Not exactly. The walrus operator (:=), introduced in Python 3.8 via PEP 572, lets you assign and test a variable in a single expression: while value := get_next():. This eliminates duplication when the same call both produces a value and serves as the loop condition. However, because the walrus form checks the condition before the body runs, it does not behave like a do while loop. If you need the body to execute unconditionally at least once, while True with break remains the correct pattern.
In modern Python (3.x), there is no practical difference. Both create an infinite loop that runs until a break is reached. The while 1: form originates from early Python, when True did not exist as a built-in name at all until Python 2.2 — and even after Python 2.2 added it, True was still a reassignable name rather than a protected keyword. User code could write True = False without error. The integer literal 1 cannot be shadowed, making while 1: the more robust choice for safety-conscious code of that era. Python 3 made True and False reserved keywords that cannot be reassigned under any circumstances (Python 3 Language Reference — Keywords). In Python 3 code, while True: is preferred for clarity. You will still encounter while 1: in older codebases and C extension authors' style guides — it is valid but dated.
continue jumps execution back to the top of the loop — back to the while True: line. Any code between the continue and the if / break at the bottom will be skipped on that pass. This means if your exit condition is at the bottom of the body and a continue fires above it, the exit condition will not be evaluated on that iteration. The loop will restart from the top instead.
Python's while loop supports an else clause that runs when the loop exits naturally — when its condition becomes false. Because while True: never becomes false on its own, the else block is unreachable: the only way out of while True: is through break, and break always suppresses the else. Writing an else block under while True: is syntactically valid but logically dead code. while/else is useful in bounded loops where exhausting all iterations without breaking is a meaningful outcome.
A break inside a try block works exactly as expected: Python runs the finally clause if one exists, then exits the loop. The break is honored and the loop does not continue. An unhandled exception that propagates out of the loop body exits the loop without executing the break — which is correct behavior, as the intended exit condition was never reached. Use except to catch transient errors you want to retry, and let fatal exceptions propagate naturally.
Yes. Inside an async def function, while True: with break works the same way structurally. The body can contain await expressions, which yield control to the event loop during the wait without blocking other coroutines. The do while guarantee is preserved: the first awaited operation always fires before any exit condition is evaluated. One important constraint: a while True: loop in async code must contain at least one await expression — otherwise it will block the event loop entirely and starve all other tasks.