Skip to main content

Loops and Iteration

A for loop processes values one at a time from an iterable—an object that supplies values for iteration, such as a list or an open file. In the first example, enumerate(values) supplies an index and a value on each iteration. In the second, zip pairs values from two inputs; strict=True reports unequal lengths rather than silently stopping at the shorter input. process and compare stand for the work your program performs on each item or pair.

for index, value in enumerate(values):
process(index, value)

for left, right in zip(left_values, right_values, strict=True):
compare(left, right)

Use range(start, stop, step) when the numbers themselves define the iteration, not merely to imitate indexing.

While loops​

A while loop repeats while a condition remains truthy. Make initialization, progress, and termination visible:

attempts = 0
while attempts < maximum_attempts:
if try_operation():
break
attempts += 1
else:
raise RuntimeError("operation never succeeded")

The loop else runs only when the loop finishes without break. It is often useful for search exhaustion, but a helper function with an early return may be clearer.

Control statements​

  • break exits the nearest loop.
  • continue starts its next iteration.
  • pass performs no operation; it is a syntactic placeholder.

Avoid deeply nested break logic; extract a function or maintain explicit state when several loops must terminate together.

Mutation during iteration​

Changing the size or structure of the container being traversed can skip values, repeat work, or raise an error. Iterate over a copy, build a new collection, or separate discovery from mutation:

active = [item for item in items if item.enabled]

Iterators are consumable​

Many iterators yield each value once. Converting to a list enables repeated passes but materializes all values. Preserve streaming when input may be large.

Bounds, exhaustion, and paired inputs​

The iteration tutorial uses a half-open interval: range excludes stop, defaults to a start of zero and a step of one, and rejects a zero step with ValueError. A step pointing away from stop produces an empty range. A range stores its bounds rather than materializing all its integers.

assert list(range(3)) == [0, 1, 2]
assert list(range(5, 0, -2)) == [5, 3, 1]
assert list(range(0, 5, -1)) == []
values = [10, 20]
it = iter(values)
assert next(it) == 10
assert list(it) == [20]
assert list(it) == []
assert list(values) == [10, 20]
assert list(enumerate(values, start=1)) == [(1, 10), (2, 20)]

An iterable supplies an iterator through iter; an iterator supplies successive values through next until StopIteration. A list can supply a fresh iterator for each traversal, but an exhausted iterator stays exhausted. for handles StopIteration for you. Without strict=True, zip stops at the shortest input; with it, unequal lengths raise ValueError during consumption, possibly after some pairs have already been processed.

Loop else also runs for an empty input or an initially false while condition. It does not run when return or an exception leaves the loop. continue in a while loop retests the condition, so skipping the progress update can create an infinite loop.

Source​

Explore connectionsOpen network