The while Loop
while repeats for as long as a condition holds. Use it when the number of repetitions is unknown, and make sure something inside the loop can make the condition false.
- Basics
- Data Types
- Operators
- Strings
- Control Flow
- Lists
- Tuples
- Sets
- Dictionaries
- Comprehensions
- Functions
- Advanced Functions
- Recursion
- Exception Handling
- File Handling
- Modules
- Standard Library
- OOP
- Advanced OOP
- Iterators and Generators
- Decorators
- Context Managers
- Descriptors and Dataclasses
- Python Internals
- Concurrency
- Regular Expressions
- Serialization
- Command Line Python
- Testing and Debugging
- Type Hints
- Performance
- Python Security
- DSA with Python
The shape of a while loop
count = 1
while count <= 5:
print(count)
count += 1 # without this line the loop never ends
print("done")Three things must be present: the condition is initialised before the loop, it is tested at the top of every iteration, and something inside the body moves it towards becoming false. Missing the third is how infinite loops happen.
for or while?
Use for when | Use while when |
|---|---|
| You have a collection to walk through | You are waiting for a condition to change |
| The number of repetitions is known in advance | The number of repetitions is unknown |
| Iterating a list, string, file or range | Reading input until the user stops |
| Almost always, in practice | Menus, retries, simulations, games |
# A counting loop written as while: possible, but not idiomatic
i = 0
while i < 5:
print(i)
i += 1
# The same thing as a for loop
for i in range(5):
print(i)Reading input until a sentinel
total = 0
while True:
entry = input("Amount (or 'done'): ")
if entry == "done":
break
total += float(entry)
print("Total:", total)while True with a break is a normal and readable Python pattern when the exit test naturally sits in the middle of the body. It is not a code smell, as long as there is a clear and reachable break.
The same loop with the walrus operator
while (entry := input("Amount (or 'done'): ")) != "done":
print("Recorded", entry)Validating input
while True:
raw = input("Enter your age: ")
if raw.isdigit() and 0 < int(raw) < 130:
age = int(raw)
break
print("Please enter a whole number between 1 and 129.")
print("Age recorded:", age)Retrying with a limit
MAX_ATTEMPTS = 3
attempts = 0
connected = False
while attempts < MAX_ATTEMPTS and not connected:
attempts += 1
print(f"Attempt {attempts}...")
connected = attempts == 3 # stands in for a real operation
if connected:
print("Connected")
else:
print("Gave up after", attempts, "attempts")Every retry loop needs an upper bound. A loop that retries until it succeeds will hang forever the day the thing it is waiting for never comes back.
Menus
notes = []
while True:
print("\n1 Add 2 List 3 Quit")
choice = input("Choose: ").strip()
if choice == "1":
notes.append(input("Note: "))
elif choice == "2":
for index, note in enumerate(notes, start=1):
print(index, note)
elif choice == "3":
print("Goodbye")
break
else:
print("Not a valid choice")Consuming a collection
queue = ["job1", "job2", "job3"]
while queue: # truthy while it has items
job = queue.pop(0)
print("processing", job)
print("queue empty")while queue: reads naturally and terminates because pop shortens the list every time. This is the classic shape for processing a work queue.
Infinite loops and how they happen
# 1. The counter is never advanced
i = 0
while i < 5:
print(i) # i never changes
# 2. The advance is outside the loop body
i = 0
while i < 5:
print(i)
i += 1 # wrong indentation, runs once after the loop
# 3. The condition can never become false
value = 1
while value != 0:
value -= 2 # 1, -1, -3, ... it steps straight past zero
# 4. A float comparison that never lands exactly
x = 0.0
while x != 1.0:
x += 0.1 # never exactly 1.0Case four is worth remembering: never test a float for exact equality in a loop condition. Use < or >, or count in integers.
If a loop hangs, press Ctrl+C to interrupt it. The traceback shows the line it was executing, which is usually the line that should have changed the condition.
while with else
n = 29
divisor = 2
while divisor * divisor <= n:
if n % divisor == 0:
print(n, "is not prime")
break
divisor += 1
else:
print(n, "is prime")The else block runs only if the loop finished because its condition became false, never if it exited through break. Read it as "no break happened". It is covered further in the loop control note.
Common mistakes
- Forgetting to advance the counter, or advancing it outside the body.
- Writing
while True:with no reachablebreak. - Testing a float for exact equality.
- Using
whileto walk a list whenforwould do it without an index. - Retrying with no maximum attempt count.
- Modifying the condition variable in only one branch of an
ifinside the loop.
Best practices
- Prefer
forunless the repetition count is genuinely unknown. - Before writing the body, write the line that will eventually end the loop.
- Put a hard limit on every retry or polling loop.
- Use
while collection:when consuming items; it reads well and terminates naturally. - Keep the body short. If it grows past a screen, extract a function.
Practice
- Write a number guessing game that gives higher or lower hints and counts the attempts.
- Sum numbers entered by the user until they type a blank line.
- Write a loop that reverses the digits of an integer using
%and//. - Explain each of the four infinite loop examples above and fix them.
- Rewrite a
whileloop that walks a list by index as aforloop.
Conclusion
Use while when you do not know how many repetitions there will be, and always know how the loop ends before you write what it does. while True with a clear break is idiomatic; a loop with no exit is a hang waiting to happen.