Embercode
✕
LoopsLesson 3 of 16

40 min read

The do-while pattern in Python

Why this matters

Some jobs must happen at least once. A menu has to appear before the user can choose anything. A program must ask for a number before it can check that the number is in range. A login screen must show its prompt before it can check the password. In each case, a loop that checks its condition first would skip the very step that gives the condition a value to test.

Some languages have a loop that runs its body first and checks the condition afterwards. It is called a do-while loop. Python does not have one. Python programmers write a while True loop and put the check at the bottom of the body. This lesson shows that pattern with exact traces, then gives you the input-checking code that uses it in real programs. Beginners either overuse this pattern or forget it exists, so the lesson also shows when a plain while loop is the better choice.

The idea from first principles

Recall how a while loop works. Python checks the condition first. Only if the condition is true does it run the body. After the body, it checks again.

while condition:
    body

A do-while loop reverses the first two steps. It runs the body, then checks the condition, and only if the condition is true does it go round again.

Python writes this with while True. The condition in that line is always true, so the loop never stops by itself. The check goes at the bottom of the body. It is an if line that calls break when the loop should stop.

while True:
    body
    if not condition:
        break

not turns true into false and false into true. break leaves the loop at once. The if line says: when the condition is no longer true, stop.

Because the check comes after the body, the body always runs at least once. That is the whole difference. Updating variables and making the condition false eventually work the same way as in a while loop.

Python has no do keyword. Writing one gives a syntax error, which the mistakes section shows.

An everyday analogy: asking a question until you get a usable answer

Think of a shop assistant who asks a customer for a size. The assistant asks once. If the answer is not a size they stock, they ask again. The first question must always be asked, because there is no answer to check before it. After that, the question repeats only while the answer is still not usable.

That is the shape of the pattern. The first question is the top of the body. The check "is the answer usable?" is the last step of the body. The repeat is the jump back to the top. A while loop would check "is the answer usable?" before any question was asked, and it would have no answer to check.

The precise version: the same loop in both forms

The program below has two loops. The first is a plain while loop. The second uses the while True pattern. Both print the numbers 1 to 3. The += operator adds a value to a variable, so i += 1 adds 1 to i.

Python · editable

The output is:

1
2
3
---
1
2
3
--- start at 10 ---
while printed nothing
10
while True printed one value

With the start at 10, the while loop checks 10 <= 3, sees that it is false, and prints nothing. The while True version prints 10 once, then adds 1, gets 11, checks 11 <= 3, and stops. The check says the value should not be printed, but the body had already printed it.

This is the test to make before you choose the pattern. Ask: can the body safely run once with the starting values? If the answer is no, use while.

Worked example 1: a menu that repeats

A menu is the classic example. The program shows the choices, reads one, and repeats until the user chooses to quit. The menu must be shown at least once, which is exactly what this pattern guarantees.

The example uses a number for each choice. Option 1 adds 10 to a total, option 2 subtracts 3, and option 0 quits.

total = 0
while True:
    print(f"Total: {total}")
    print("1) add 10   2) subtract 3   0) quit")
    choice = int(input())
    if choice == 1:
        total += 10
    elif choice == 2:
        total -= 3
    if choice == 0:
        break
print(f"Final total: {total}")

Input, one value per line:

1
1
2
0

The output is:

Total: 0
1) add 10   2) subtract 3   0) quit
Total: 10
1) add 10   2) subtract 3   0) quit
Total: 20
1) add 10   2) subtract 3   0) quit
Total: 17
1) add 10   2) subtract 3   0) quit
Final total: 17

input() reads one line of text and returns it. int(...) turns that text into a whole number. The f before a string lets you put a value inside it. f"Total: {total}" prints Total: 10 when total is 10.

Trace the loop. The first pass prints the menu with a total of 0, reads 1 and adds 10. The second pass shows 10, reads 1 and adds 10 again, which makes 20. The third pass reads 2 and subtracts 3, leaving 17. The fourth pass reads 0. The stop check choice == 0 is true, so the loop ends. The menu appeared four times, and the body ran four times, because the check is at the bottom.

Python does not need choice declared before the loop. A name set in the body exists after the first pass, so the check at the bottom can read it.

The menu is a good model for this design. Show the menu, read the choice, act on it, then check whether to continue. Every menu-driven program follows that shape.

Worked example 2: the digit sum of zero

The while loop lesson earlier in this module counted digits with while rest > 0. For the number 0, the condition is false from the start, so the loop never ran and the digit count was 0. That is wrong, because 0 has one digit, the digit 0 itself.

This version runs the body once before the check, so the digit 0 is counted, and then the number becomes 0 and the loop stops.

n = int(input())
digits = 0
digit_sum = 0
while True:
    digit_sum += n % 10
    n //= 10
    digits += 1
    if n == 0:
        break
print(f"Digits: {digits}")
print(f"Digit sum: {digit_sum}")

n % 10 is the last digit of n, which is the remainder after dividing by ten. n //= 10 removes the last digit, because // is integer division, which keeps only the whole part of the result.

Input: 0

The output is:

Digits: 1
Digit sum: 0

Now try input 1234. The output is Digits: 4 and Digit sum: 10. The two loops agree for every positive number. They differ only for zero, and this version is correct for zero because the digit 0 really is one digit.

Python integers have no size limit, so there is no long type to choose, as in some other languages. For example, the program prints Digits: 31 for the number 2 to the power of 100, which is 1267650600228229401496703205376.

This example teaches a general rule. When a loop body is correct for an input that is zero or empty, the pattern often handles that input more naturally. When the body would be wrong for that input, a while loop is safer. Decide based on what the correct answer is for the edge case, not on what looks shorter.

Worked example 3: validating input until it is in range

The most important use of this pattern in real programs is input validation. The program asks for a value, checks that it is in the allowed range, and asks again if it is not. The question must be asked first, and the check comes after, so this pattern fits.

The rule here is that the number must be from 1 to 10.

while True:
    value = int(input("Enter a number from 1 to 10: "))
    if 1 <= value <= 10:
        break
    print("That is not in range. Try again.")
print(f"Accepted {value}")

Input, one value per line:

0
12
7

The output is:

Enter a number from 1 to 10: That is not in range. Try again.
Enter a number from 1 to 10: That is not in range. Try again.
Enter a number from 1 to 10: Accepted 7

The loop keeps going while the value is out of range. So the stop check is "the value is in range", which Python writes as 1 <= value <= 10. Python lets you chain two comparisons like this. It means the same as 1 <= value and value <= 10.

input("...") prints the text you give it, then waits. The text has no newline after it, so in this output the three prompts run together on one line. When you run the program in a terminal, each prompt waits for you to type.

A plain while loop would need the value read once before the loop and again at the bottom. That is the priming read from the while lesson, and it repeats code. The while True version reads the value inside the body, once per pass, which is where it belongs.

Worked example 4: reading words until a stop word

The menu and the validator read numbers. The same pattern works for text. This example reads words until it sees the word stop, then prints how many words came before it.

input() reads a whole line, so this program expects one word per line.

count = 0
while True:
    word = input()
    if word == "stop":
        break
    count += 1
print(f"Words before stop: {count}")

Input, one word per line:

apple
banana
cherry
stop

The output is:

Words before stop: 3

The check word == "stop" compares the text. In Python, == on two strings compares their letters, so no separate method is needed. The != operator means "is not equal".

The body reads one word, and the check comes right after the read. The stop word itself is not counted, so the count is 3, not 4.

Worked example 5: a PIN with three tries

A common security rule lets a user try a code three times, then locks the account. The program must ask at least once, and it must check each try against the stored code. The check decides whether to ask again, and the limit decides whether the user may try again at all. The loop has two rules in its stop check.

The stored code is 4821 in this example.

secret = 4821
tries = 0
unlocked = False
while True:
    guess = int(input())
    tries += 1
    if guess == secret:
        unlocked = True
    if unlocked or tries >= 3:
        break
if unlocked:
    print(f"Unlocked after {tries} tries")
else:
    print(f"Locked after {tries} tries")

Input, one value per line:

1234
4821

The output is:

Unlocked after 2 tries

The loop keeps going while the user is still locked out and has tries left, which is not unlocked and tries < 3. The stop check is the opposite: unlocked or tries >= 3. The or means that either part being true is enough to stop.

Trace the loop. The first pass reads 1234. The count goes to 1. The code does not match, so unlocked stays false, and the check does not stop the loop. The second pass reads 4821, and the count goes to 2. The code matches, so unlocked becomes true, and the check stops the loop. The program reports two tries.

Now type three wrong values, 1, 2 and 3. The count reaches 3, so tries >= 3 is true, and the loop ends with unlocked still false. The output is Locked after 3 tries.

unlocked = False is set before the loop for a reason. The stop check reads unlocked after the first pass, but the if that changes it may not run. If the name were never set, Python would raise an error at the check.

Worked example 6: a guessing game with hints

A guessing game is a good example of this pattern where the body gives feedback. The secret number is fixed, so the output is always the same, and you can test it. The first guess must be read before any comparison can happen, so the first step is always inside the loop.

secret = 42
guesses = 0
while True:
    guess = int(input())
    guesses += 1
    if guess < secret:
        print("Too low")
    elif guess > secret:
        print("Too high")
    if guess == secret:
        break
print(f"Correct in {guesses} guesses")

Input, one value per line: 10, 99, 42.

The output is:

Too low
Too high
Correct in 3 guesses

Trace the program. The first guess is 10. It counts as guess 1, and 10 is less than 42, so the program prints Too low. The stop check is false, so the loop repeats. The second guess is 99, which is guess 2. It is greater than 42, so the program prints Too high. The third guess is 42, which is guess 3. Nothing is printed by the if and elif lines, because the value matches. The stop check is true, the loop ends, and the program prints the count.

Reading a while True loop from the bottom

When you read a while True loop in someone else's code, start at the bottom. The if near the end says when the loop stops, and you must know what the body set before that check. Then read the body from the top, and find the line that changes each variable in the check.

Follow these four steps for the guessing game. First, the bottom says if guess == secret: break, so you need to know the value of guess after the body. Second, the body reads guess from input, so the value is whatever the user typed on the last pass. Third, the body also changes guesses, which is not in the stop check but is in the answer. Fourth, the body prints a hint when the guess is wrong, and prints nothing when it is right. From these steps you can predict the whole output before you run the code.

Choosing between while and this pattern

When you need a loop that repeats, first decide whether the body must run before any check can happen. If the answer is yes, use while True with the check at the bottom. If the body may need to run zero times, use while. The table below gives the questions that decide most cases.

QuestionIf yesIf no
Must the body run at least once, even if the answer would say stop?while True with the check at the bottomwhile
Does the check need a value that only the body can create?while True with the check at the bottomwhile, with a priming read before the loop, or for if the count is known
Is the input allowed to be empty, so zero passes are correct?whilewhile True with the check at the bottom is fine
Is the number of passes known before the loop starts?forEither form

A short way to remember the rule: "do this, then decide" suits the pattern, and "decide, then do this" suits while. A menu is "show, then decide", so it fits the pattern. Reading a list until the end is "decide, then read", so it is a while or a for.

What happens inside a while True loop

Python does not run a special check before the first pass of a while True loop. The condition is always true, so Python enters the body. At the bottom, the if tests the stop condition. If the test is true, break leaves the loop. If not, Python goes back to the top of the body.

Each pass does one body run and one test. A plain while loop does the same work, so there is no speed reason to choose one form over the other. Choose the form that matches the problem.

Python does not give a loop its own scope. A name set inside the body still exists after the loop. A name that the body never sets does not exist at all, so a check that reads it fails. The edge cases section shows that failure.

Edge cases for this pattern

This pattern has its own set of edge cases. Check each one before you trust the loop.

The first is the body that must not run. Because the body always runs once, check what happens when the starting data is empty. A menu with no options is a bad design, and the pattern would still show it once. A program that reads a first item before it checks whether any items exist will fail on empty input. When input() has no line left to read, it raises EOFError.

The second is the check that uses a value the body may not have set. Python does not check this before the program runs. It raises NameError when the check runs, and only if the name is missing on that pass. The mistakes section shows the message. Give the variable a starting value before the loop, such as choice = 0, when the body may skip the assignment. A starting value can also hide a bug, so set it on purpose.

The third is the counter that never changes. A validator whose body reads a value but never increments a counter cannot give up after a limit. Always check that the counter in the stop check moves on every pass.

The fourth is the value that is valid on the first pass but not later. A menu that changes a total can produce a total that is out of range after several passes, and the check must test the total, not the first value. Trace at least three passes when the loop has state.

A trace table for the menu

Tracing this pattern uses the same table as the other loops, with one column for each variable the body or the check uses. The table below traces the menu from worked example 1 with the input 1, 1, 2, 0. Each row is one pass, and the stop check is made at the end of the row.

PassTotal at the startChoice readTotal after the bodyStop check choice == 0
10110false, repeat
210120false, repeat
320217false, repeat
417017true, stop

Read the table from left to right. The menu line is printed at the start of each pass, which is why the total shown at the start of pass 2 is 10. The choice is read in the middle of the body. The stop check is made last, and it sees the choice that was just read. The row with a true check is the last pass, and the program then prints the final total.

Notice that the total on row 4 is the same as on row 3. The choice 0 adds nothing, which is why the program can quit without a special case.

Input that is not a number

The validator in worked example 3 uses int(...), so text such as ten stops the program with an error. The better design catches the error and asks again.

A try block runs code that might fail. If the code fails, the except block runs instead of the program stopping. The example below catches a bad value and asks again.

while True:
    text = input("Enter a number from 1 to 10: ")
    try:
        value = int(text)
    except ValueError:
        print(f"Not a whole number: {text}. Try again.")
        continue
    if 1 <= value <= 10:
        break
    print("Out of range. Try again.")
print(f"Accepted {value}")

Input, one value per line:

abc
15
7

The output is:

Enter a number from 1 to 10: Not a whole number: abc. Try again.
Enter a number from 1 to 10: Out of range. Try again.
Enter a number from 1 to 10: Accepted 7

Look at the continue. In a while True loop, continue jumps to the top of the body, and the check at the bottom is skipped. Here that is the right result, because the top of the body asks for a new value. Make sure the check at the bottom does not depend on a value that the skipped lines would have set.

Use this pattern when the program must keep running after bad input. A program that stops on the first bad word is easier to write, but it is a poor experience for a user who typed one wrong key.

Interview angle: validation and the one-pass guarantee

Interviewers rarely ask you to write a do-while loop by name. They ask about input validation, menus or retry logic, and the best answer uses this pattern naturally. Explain the choice in one sentence: the body must run before the check can use the value. That shows you know why the loop is right, which matters more than the syntax.

Expect a follow-up about empty input. A loop that reads a number runs once, and if no input is left, input() raises EOFError. A careful answer checks for empty input before the first read, or states that the input is guaranteed to have at least one value. Saying which assumption you made is a strong answer.

Expect a question about retries. A validator that gives up after a limit uses a counter in the stop check, as in the PIN example. Mention the counter, say where it is updated, and say what the program prints when the limit is reached. A clear answer covers the success path, the failure path and the limit.

Common mistakes

Writing a do keyword

Python has no do loop, so this code fails:

do:
    print("Once")
while True

The error is:

  File "/path/to/main.py", line 1
    do:
       ^
SyntaxError: invalid syntax

The first line of the message shows the path of your file, which depends on where you save it. The caret points just after the colon. Python stopped reading there, because do is not a statement it knows. Replace the whole block with the while True pattern.

Forgetting the break

A while True loop with no break never stops. Python gives no error for this. The program keeps running until you stop it, for example with Ctrl+C. Check that every while True loop has a break on a path that can run, and that the check before the break can become true.

Using the text from input() as a number

input() always returns text. The comparison choice == 1 compares text with a number, and text never equals a number in Python, so the if never runs. This program has that bug:

total = 0
while True:
    print(f"Total: {total}")
    choice = input()
    if choice == 1:
        total += 5
    if choice == "0":
        break
print(f"Final total: {total}")

Input, one value per line: 1, then 0.

The output is:

Total: 0
Total: 0
Final total: 0

The program does not raise an error. The total never changes, which is harder to spot. Wrap the read in int(...), as the examples do, and compare with a number.

Adding text to a number

If you change the program so that total is a number and choice is still text, the addition fails:

total = 0
while True:
    choice = input()
    total += choice
    if choice == "0":
        break
print(total)

Input, one value per line: 1, then 0.

The error is:

Traceback (most recent call last):
  File "/path/to/main.py", line 4, in <module>
    total += choice
TypeError: unsupported operand type(s) for +=: 'int' and 'str'

The message says that += cannot join a number and text. The fix is the same as before: convert the text with int(...).

Using a name the body may not have set

This program sets value only when the input is go. The check reads value on every pass, so a different input makes the check fail:

while True:
    if input() == "go":
        value = 5
    if value == 5:
        break
print(value)

Input, one value per line: no, then no.

The error is:

Traceback (most recent call last):
  File "/path/to/main.py", line 4, in <module>
    if value == 5:
       ^^^^^
NameError: name 'value' is not defined. Did you mean: 'False'?

The message names the missing variable. The suggestion at the end is generated by Python and can be unhelpful. The fix is to set value before the loop, so the name exists on every pass.

Using this pattern when the body must not run

The pattern runs its body once even if the starting values say it should not. This loop is meant to print nothing for a start of 0, but it prints 0 once:

n = 0
while True:
    print(n)
    n -= 1
    if not n > 0:
        break

The output is:

0

The fix is a plain while loop with the check first. Before you choose this pattern, check what the body does when the starting values are empty, zero or invalid.

Reading text that is not a number

If the user types text where int(...) expects a number, the program stops with an error:

value = int(input())
print(value)

Input: ten

The error is:

Traceback (most recent call last):
  File "/path/to/main.py", line 1, in <module>
    value = int(input())
ValueError: invalid literal for int() with base 10: 'ten'

The message names the value that could not be converted. Use the try and except example in the section above to keep the program running.

Debugging walkthrough: a menu that never adds 5

A learner wrote the menu below. It should show the total each time, add 5 when the user types 1, and stop when the user types 0. The total never changes.

total = 0
while True:
    print(f"Total: {total}")
    choice = input()
    if choice == 1:
        total += 5
    if choice == "0":
        break
print(f"Final total: {total}")

Step 1: read the symptom. The total stays at 0 after the user types 1. The menu runs, so the loop works. The problem is in the step that should add 5.

Step 2: find the if that should add. It is choice == 1. The user typed 1, so the if should be true.

Step 3: check the type of choice. Add a line such as print(type(choice)) before the if. For the input 1, it prints <class 'str'>. The value is text, so it is not equal to the number 1.

Step 4: find the cause. input() returns text. The text "1" never equals the number 1, so the if is always false. The stop check uses "0" as text, so it works, but the two checks are inconsistent.

Step 5: fix the code. Convert the input once, and compare with numbers. The fixed program is:

total = 0
while True:
    print(f"Total: {total}")
    choice = int(input())
    if choice == 1:
        total += 5
    if choice == 0:
        break
print(f"Final total: {total}")

Input, one value per line: 1, then 0. The output is:

Total: 0
Total: 5
Final total: 5

The lesson is the one from the earlier debugging walkthroughs. Trace the expected output by hand, then compare each step with the code. A value that looks like a number can still be text, and type(...) shows which one you have.

Edge cases and interview patterns

Interviewers rarely ask for this pattern directly, but they ask about the situations it solves. Here are the common ones.

The first is the empty input. A loop that reads at least one value fails when no input is left, with EOFError. The fix is to check for an empty input before the first read, or to state the assumption. Mention this when you explain your design.

The second is the zero case. As shown above, a digit loop is correct for zero only with this pattern or with a special case. Interviewers often include zero in their tests, so check it.

The third is the retry limit. A validator that stops after three tries needs a counter and a second condition. Write the stop check as "the value is valid, or there have been three tries". That is the pattern with two parts in the check, which shows you can combine rules.

The fourth is the menu. Menu programs are a standard exercise, and the question is usually about state: what must the program remember between choices, and when does it quit? The total in the menu example is the state. Name it clearly.

When you explain your choice to an interviewer, say why the body must run once. A short answer such as "the menu must be shown before the user can choose" is enough, and it shows that you chose the loop on purpose.

Real-world uses

Many programs use this shape. A login form asks for a password, then checks it, then asks again if the password was wrong. A tool that sends a request, then checks the reply, then sends again if the reply was an error. A game asks the player for a move, applies it, then checks whether the game is over. A command-line tool shows its prompt, reads a command, runs it and loops until the user types exit.

In each case, the first action is part of the loop, not a setup step before it. If you can say "do this, then check whether to do it again", you have found a problem for this pattern. If you need to check first, use while.

Practice

Try each exercise before you open the answer. For each one, decide whether while or the while True pattern fits, and say why in a short sentence.

  1. Print the numbers 5 down to 1 using the while True pattern. Then change the start to 0 and predict the new output before you run it.

Show the answer

i = 5
while True:
    print(i)
    i -= 1
    if i < 1:
        break

The output is 5, 4, 3, 2, 1, one per line. If the start were 0, the body would still run once and print 0.

  1. Read integers until the user types 0. Print the total of the numbers entered, not counting the 0.

Show the answer

total = 0
while True:
    value = int(input())
    if value == 0:
        break
    total += value
print(total)
  1. Read an integer and print its digit count with the while True pattern, so that 0 gives 1.

Show the answer

n = int(input())
digits = 0
while True:
    n //= 10
    digits += 1
    if n == 0:
        break
print(digits)
  1. Write a validator that asks for an age from 0 to 120 and keeps asking until the answer is valid.

Show the answer

while True:
    age = int(input())
    if 0 <= age <= 120:
        break
print(age)
  1. Write a menu with options 1 to double a number, 2 to add 7, and 0 to quit. Start the number at 3. Print the final number.

Show the answer

number = 3
while True:
    choice = int(input())
    if choice == 1:
        number *= 2
    elif choice == 2:
        number += 7
    if choice == 0:
        break
print(number)
  1. Read words until the word end. Print the length of each word, using len.

Show the answer

while True:
    word = input()
    if word == "end":
        break
    print(len(word))
  1. Predict what this prints, and explain why the body ran at all.
x = 5
while True:
    x += 1
    if not x < 5:
        break
print(x)

Show the answer

The output is 6. The body runs once before the check, so x becomes 6. The check 6 < 5 is false, so the loop stops, and the program prints 6.

  1. Change the validator from worked example 3 so that it gives up after three invalid tries and prints Too many tries.

Show the answer

tries = 0
while True:
    value = int(input())
    tries += 1
    if 1 <= value <= 10:
        break
    if tries == 3:
        print("Too many tries")
        break
  1. Explain in one or two sentences why the while True pattern is the wrong choice for "print each item in a list that might be empty".

Show the answer

The pattern runs its body once even when the list is empty, so it would try to handle an item that does not exist. A for loop over the list checks first, so an empty list prints nothing.

  1. Find and fix the bug. The program should print the total of the numbers entered, not counting the 0. Input, one value per line: 3, 4, 0.
total = 0
while True:
    v = int(input())
    total += v
    if v != 0:
        break
print(total)

Show the answer

The check is reversed. The loop stops at the first value that is not 0, so this program prints 3 for that input. The fix is to stop when the value is 0, and add only the other values:

total = 0
while True:
    v = int(input())
    if v == 0:
        break
    total += v
print(total)

With the input 3, 4, 0, the fixed program prints 7.

What you now know

  • Python has no do-while loop. The while True loop with an if and break at the bottom runs the body first, then checks.
  • Use the pattern for menus, validation and any step that must happen before the check can make sense.
  • Convert input with int(...) before you compare it with a number. input() always returns text.
  • A name the body sets is still there after the loop. A name the body never sets fails with NameError when a check reads it.
  • Check whether the body is correct for empty, zero or invalid starting values before you choose the pattern over while.
  • A validation loop reads the value inside the body and repeats until it is in range.

The next lesson covers break and continue in more detail, including how to leave nested loops in Python, which has no labels.

Practice this topic: coding problems for Loops →

Stuck? Ask the tutor

Ask about anything in this lesson. Answers are short and use simple words.

Sign in to ask the tutor.

← The while loop in Python