Notifications

No notifications

/Phase 2

Loops in Python

Loops in Python 🔄

Loops let you repeat a block of code multiple times. Python provides two main loop types: for and while.

for Loop

Iterates over a sequence (list, string, range, etc.):

for i in range(5):
    print(i)  # 0, 1, 2, 3, 4

while Loop

Repeats as long as a condition is True:

count = 0
while count < 5:
    print(count)
    count += 1

Loop Control Statements

StatementDescription
breakExit the loop immediately
continueSkip current iteration, go to next
passDo nothing — placeholder

Useful Built-in Functions

FunctionPurposeExample
range(n)Generate numbers 0 to n-1range(5) → 0,1,2,3,4
range(a, b)Generate numbers a to b-1range(2, 6) → 2,3,4,5
range(a, b, step)With steprange(0, 10, 2) → 0,2,4,6,8
enumerate(seq)Index + value pairsenumerate(["a","b"]) → (0,"a"),(1,"b")
zip(a, b)Pair elements from two sequenceszip([1,2],["a","b"]) → (1,"a"),(2,"b")

Nested Loops

for i in range(3):
    for j in range(3):
        print(f"({i},{j})", end=" ")
    print()

Loop-Else

The else block after a loop runs only if the loop did not exit via break:

for n in range(2, 10):
    if n % 7 == 0:
        print(f"Found {n}!")
        break
else:
    print("No multiples of 7 found")

> Tip: Prefer for loops when the number of iterations is known. Use while when the termination depends on a dynamic condition.

On this page

Detailed Theory

Loops are how programs *do the same thing many times* — send 100 emails, scan 10,000 rows, retry until success. Python gives you two: for (iterate over a collection) and while (repeat while a condition holds). Master these and you've unlocked half of all real-world code.

What a Loop Actually Is

A loop is a controlled jump back to an earlier line. Each cycle is an iteration. Python's loops are built on the iterator protocol — anything that knows how to give one item at a time can be looped.

The for Loop

for name in ["Anu", "Ben", "Cara"]:
    print("hi", name)

Unlike C/Java, Python's for doesn't count — it walks straight through items. Almost everything is iterable: lists, tuples, strings, dicts, sets, files, generators, ranges.

The while Loop

count = 3
while count > 0:
    print(count)
    count -= 1

Use while when you don't know the iteration count upfront (retry loops, game loops, reading until EOF).

range() — Counting Numbers

range(5)         # 0,1,2,3,4
range(2, 8)       # 2,3,4,5,6,7
range(0, 10, 2)   # 0,2,4,6,8
range(10, 0, -1)  # countdown

range is lazyrange(10**9) uses negligible memory because numbers are computed on demand.

break, continue, else

for n in nums:
    if n < 0:
        continue       # skip this iteration
    if n > 100:
        break          # exit the loop
    process(n)
else:
    print("loop finished without break")

The loop's else runs only if the loop *wasn't* broken — useful for search loops.

Beginner Mistakes to Skip

1. for i in range(len(items)): then items[i]. Just write for item in items. Use enumerate if you need the index. 2. Modifying a list while iterating it. Items get skipped or repeated. Iterate a copy (for x in items[:]) or build a new list. 3. Infinite while with no exit. Forgot to update the loop variable? Hang. Always make sure progress is guaranteed. 4. Using == to test floats in a while. Floating-point drift means the condition may never be exactly hit. Use <= / >= or a tolerance. 5. while True: break forests. Re-think the condition; usually a single boolean expression is cleaner. 6. Building a list with += [x] in a loop. Use .append(x) (faster, clearer) or a list comprehension.

Intermediate: enumerate, zip, reversed

for i, name in enumerate(names, start=1):
    print(i, name)

for name, score in zip(names, scores): print(name, score)

for x in reversed(items): ...

  • enumerate → (index, value) pairs.
  • zip → parallel iteration; stops at the shortest. Use itertools.zip_longest to pad.
  • reversed → walks back-to-front without copying.

Intermediate: Comprehensions — Loops as Expressions

squares   = [x*x for x in range(10)]
evens     = [x for x in nums if x % 2 == 0]
pairs     = [(x, y) for x in xs for y in ys if x != y]
lengths   = {name: len(name) for name in names}
uniques   = {x.lower() for x in tags}

List / dict / set comprehensions are faster than for + append because the loop runs in C. Keep them readable — if it needs more than two clauses or nested ifs, use a regular for.

Intermediate: The Iterator Protocol

it = iter([10, 20, 30])
next(it)   # 10
next(it)   # 20
next(it)   # 30
next(it)   # raises StopIteration

A for loop is just sugar over this. Anything that defines __iter__ and __next__ is iterable — your custom classes can plug straight into for.

Intermediate: Generators — Lazy Loops

def squares_up_to(n):
    for i in range(n):
        yield i * i

for s in squares_up_to(1_000_000): if s > 100: break

yield pauses the function; the next iteration resumes it. Generators stream values one at a time — huge memory savings on big data.

Generator *expressions* mirror comprehensions with parentheses: sum(x*x for x in nums).

Advanced: itertools — The Loop Toolbox

The itertools standard module provides battle-tested building blocks:

from itertools import chain, islice, groupby, accumulate, product, combinations

for x in chain(list_a, list_b): ... # concatenate iterables for x in islice(stream, 100): ... # first 100 of a stream for key, group in groupby(rows, key=...): # SQL-style grouping (requires sorted input) for total in accumulate(nums): # running sum for a, b in product(xs, ys): ... # cartesian product for combo in combinations(items, 3): ... # all 3-element subsets

If you ever feel like writing nested loops with index math, check itertools first.

Advanced: Performance Patterns

  • Hot loops: pull attribute lookups out (append = lst.append; for x in items: append(x*2)).
  • Prefer vectorised ops with NumPy / Pandas instead of Python loops on numeric data — often 100×+ faster.
  • Use any() / all() with generator expressions for short-circuit checks: if any(x < 0 for x in nums): ....
  • Replace manual counters with collections.Counter and grouping loops with defaultdict(list).

Advanced: Async Loops (async for)

When iterating over an async stream (websocket, HTTP responses, DB rows):

async for message in websocket:
    await handle(message)

This is non-blocking — other coroutines can run between iterations. Pairs with async def and await. (Covered in depth alongside concurrency.)

Practice Path

1. Sum 1…100 using for + range, then again with sum(range(...)) and compare line counts. 2. Use enumerate to print "1. Anu, 2. Ben, ..." from a list of names starting at 1. 3. Convert this loop into a list comprehension: out = []\nfor x in nums:\n if x > 0: out.append(x*2). 4. Write a generator fib() that yields Fibonacci numbers forever, then take the first 20 with itertools.islice.