Loops and Conditions in Python: for, while, range, enumerate, break, if/elif and match/case
Loops in Python repeat an action: for goes through the items of any collection or range(), while runs as long as its condition is true. You can stop a loop with break, skip an iteration with continue, and get the item number with enumerate(). Decisions are made with if/elif/else, and data can be sorted by shape with match/case (since Python 3.10).
Loops in Python let you repeat an action: go through a shopping list, process each line of a file, or keep asking the user until they enter a valid number. The language has two loops — for and while — and inside them the if/elif/else conditions and the match/case statement help you make decisions. Let us go through each tool with working examples.
Conditions: if, elif, else
An if statement runs a block of code only when its expression is true. The block is marked by an indentation of 4 spaces — Python has no curly braces, and a wrong indentation immediately causes an IndentationError.
spent = 4200
limit = 5000
if spent > limit:
print("Limit exceeded")
elif spent > limit * 0.8:
print("Less than 20% of the budget left")
else:
print("All good")
The elif branches are checked from top to bottom, and only the first matching one runs. That is why stricter conditions go higher up: if the check spent > limit * 0.8 came first, the message about exceeding the limit would never appear.
What counts as true
You do not always have to write a comparison in a condition. The values treated as false are False, None, zero (0, 0.0) and empty collections: "", [], {}. Everything else is true. That is why the check "the list is not empty" is written briefly:
expenses = []
if not expenses:
print("No expenses yet")
Conditions can be combined with and, or and not, and a range is conveniently checked with a chained comparison: if 0 < amount <= 100_000:. For a short choice of value there is the ternary operator: status = "high" if spent > limit else "normal".
The for loop in Python: syntax and examples
The for loop in Python is not a counter, as in C, but an iteration over items. It takes each element of an iterable object in turn: a list, a string, a dictionary, a file or a range. This ordinary for is what other languages call foreach.
expenses = [350, 1200, 89, 4500]
total = 0
for amount in expenses:
total += amount
print(total) # 6139
The syntax of a for loop is for variable in collection:, followed by an indented block. After the loop the variable keeps its last value — sometimes that is useful, but relying on it in large programs is not a good idea.
Looping over a string, a list and a dictionary
A string is iterated character by character, a list item by item. A loop over a dictionary goes over the keys by default; to get the key and the value together, use .items():
by_category = {"food": 3200, "transport": 900, "cinema": 600}
for category, amount in by_category.items():
print(f"{category}: {amount}")
To get only the values, use .values(). You cannot change the size of a dictionary during iteration — you will get RuntimeError: dictionary changed size during iteration. If you need to remove items, iterate over a copy: for key in list(d):.
The range function: looping over numbers
When you need to iterate over numbers, range() comes to the rescue. It does not create a list in memory but yields the numbers one at a time, so range(10**9) works instantly.
| Call | Numbers |
|---|---|
range(5) | 0, 1, 2, 3, 4 |
range(2, 6) | 2, 3, 4, 5 |
range(0, 10, 3) | 0, 3, 6, 9 |
range(5, 0, -1) | 5, 4, 3, 2, 1 |
The main rule: the right boundary is not included. range(1, 10) ends at 9 — a frequent cause of "off-by-one" errors. The step can be negative, but not zero.
for i in range(1, 4):
print(f"Day {i}")
# Day 1
# Day 2
# Day 3
enumerate: a counter in a loop
Beginners often write for i in range(len(items)) to know the item's number. It works, but it reads worse. The enumerate() function yields pairs "number, item", and the start parameter sets the number to count from:
items = ["coffee", "taxi", "lunch"]
for n, item in enumerate(items, start=1):
print(n, item)
# 1 coffee
# 2 taxi
# 3 lunch
For iterating over two lists in parallel there is zip(): for name, price in zip(names, prices):. It stops at the shortest list; since Python 3.10 you can pass strict=True, and then lists of different lengths raise an error.
The while loop in Python
A while loop repeats its block as long as the condition is true. It is chosen when the number of repetitions is not known in advance: waiting for correct input, reading data until the end, repeating a request until it succeeds.
balance = 10_000
month = 0
while balance > 0:
balance -= 2_700
month += 1
print(f"The money lasts for {month} months") # 4
The main danger is forgetting to change the variable used in the condition. Then the loop never ends. If the program seems frozen, press Ctrl+C: Python will interrupt execution with a KeyboardInterrupt.
Infinite loops and do while
Sometimes an infinite loop in Python is written on purpose: while True: with an exit through break. The same trick is used for a loop with the condition at the end — Python has no do while construct, and this pattern replaces it: the body runs at least once, and the check comes at the end.
while True:
raw = input("Amount: ")
if raw.isdigit():
amount = int(raw)
break
print("Please enter a whole number")
A for loop is rarely infinite — only when it iterates over an endless iterator, for example itertools.count().
break and continue: leaving a loop and skipping an iteration
break stops the loop immediately, and execution continues with the code after it. continue skips the rest of the current iteration and moves on to the next one.
expenses = [350, -10, 1200, 0, 99_999, 89]
for amount in expenses:
if amount <= 0:
continue # skip this iteration
if amount > 50_000:
print("Suspicious amount, stopping")
break # leave the loop
print(amount)
This prints 350 and 1200, then the message — the loop never reaches 89. Both statements act only on the nearest loop they are in.
else on a loop
for and while have an unusual else branch: it runs if the loop finished on its own, without a break. This is handy for searching:
for amount in expenses:
if amount > 50_000:
print("Found a large expense")
break
else:
print("No large expenses")
Nested loops
A loop inside a loop runs the inner one completely on every iteration of the outer one. This is how you walk through tables and matrices or iterate over pairs.
for row in range(1, 4):
for col in range(1, 4):
print(row * col, end="\t")
print()
Keep two things in mind. First, the complexity grows quickly: two nested loops over 10,000 elements mean 100 million operations. Second, break leaves only the inner loop. To stop both, move the loops into a function and use return — that is cleaner than flags.
The match/case statement
Since Python 3.10, a long chain of if cmd == ... elif ... can be replaced with the match statement (PEP 634). It is not just a switch: it matches a value against a pattern by the shape of the data and immediately unpacks the parts into variables.
def parse(text):
match text.split():
case ["add", item, amount]:
return f"Add {item}: {amount}"
case ["list"] | ["ls"]:
return "Show expenses"
case ["quit"]:
return "Exit"
case _:
return "Unknown command"
print(parse("add Coffee 250")) # Add Coffee: 250
print(parse("add Coffee")) # Unknown command
The list pattern ["add", item, amount] matches only a list of exactly three elements, the first of which is "add". So a command without an amount goes to the _ branch, which catches everything else. The | symbol combines alternatives.
Dictionaries, types and guard conditions
A dictionary pattern checks only the keys listed; extra keys are ignored. The entry int(a) checks the type and captures the value, and an if after the pattern adds an extra condition (a guard):
match event:
case {"type": "expense", "amount": int(a)} if a > 10_000:
print("Large expense", a)
case {"type": "expense", "amount": int(a)}:
print("Expense", a)
The main trap of match
A bare name in a case is a capture, not a comparison with a variable. case limit: matches any value and writes it into limit. To compare with constants, use a dotted name such as case Color.RED:, or literals.
The match syntax has barely changed since 3.10. Python 3.15 closed a small asymmetry: in literal patterns only a minus sign in front of a number used to be allowed, and now you can also write case +1:. On older versions such code will raise a syntax error.
Common mistakes in loops
- Changing a list during iteration. Removing items inside a
forskips the neighbouring ones. It is better to build a new list:clean = [x for x in items if x > 0]. - The range boundary.
range(1, n)does not includen. - Forgetting to change the condition in while — an infinite loop.
- Concatenating strings in a loop with += is slower on large volumes than
"".join(parts). - Assignment instead of comparison:
if x = 5is a syntax error; comparison is written with==.
Loop exercises for practice
- Calculate the sum and the average of a list of expenses, skipping negative values.
- Print the multiplication table from 1 to 9 with nested loops.
- Ask the user for numbers until they enter an empty line, then print the maximum.
- Find the first number greater than 1000 in a list and report if there is none (use
for ... else). - Parse the commands
add,delandlistwithmatch.
Summary
Python loops come down to two constructs: for iterates over the items of a collection or range(), and while keeps working while its condition holds. break and continue control the flow of a loop, enumerate() and zip() spare you manual counters, and if/elif/else with match/case handle decisions. All these tools are practised on an expense tracker example in a lecture of our Python course.
FAQ
How is for different from while in Python?
for goes over a ready-made sequence and knows by itself when to stop, while repeats as long as the condition is true. If the number of repetitions is known or you have a collection, use for; if you are waiting for an event, use while.
How do I loop in reverse order?
Use reversed(items) for a collection or range(n - 1, -1, -1) for numbers. The reversed function does not copy the list; it iterates over it from the end.
Does Python have a switch statement?
There is no separate switch: its role is played by if/elif chains and the match/case statement introduced in Python 3.10. match can do more: it breaks lists and dictionaries down by shape and captures values.
Which is faster — a loop or a list comprehension?
A list comprehension such as [x * 2 for x in items] is usually a little faster than the equivalent loop with append, and shorter. For complex logic with several conditions, a regular loop is easier to read.
How do I exit two nested loops at once?
break only exits the inner loop. The simplest approach is to move the loops into a function and exit with return.
This topic is covered in depth with practice in the course “Python 3.15: от новичка до профи”.
Go to course