Skip to content

The for Loop & The Iterator Protocol

The for loop is the workhorse of Python data processing. Unlike the while loop, which runs until a condition changes, the for loop is designed for Definite Iteration—it executes once for every item in a collection (an Iterable).

To master the for loop, you must understand the “contract” between the loop and the data it traverses.


In Python, the for loop doesn’t use a counter (like i++ in C). Instead, it “asks” the collection for its next item.

simple_for.py
fruits = ["Apple", "Banana", "Cherry"]
for fruit in fruits:
print(f"Current fruit: {fruit}")
  1. Collection: fruits is the iterable.
  2. Variable: fruit is a temporary label that points to the current object.
  3. Flow: Python automatically stops when there are no items left. No IndexError is possible!

When you need to iterate a specific number of times, or need an index, Python provides the range() generator.

  • range(5) -> 0, 1, 2, 3, 4 (Starts at 0, ends before 5)
  • range(2, 6) -> 2, 3, 4, 5
  • range(0, 10, 2) -> 0, 2, 4, 6, 8
counting.py
# Calculate the sum of numbers 1 to 100
total = 0
for n in range(1, 101):
total += n
print(total) # 5050

This is the “secret sauce” of Python. When you write for item in collection:, Python performs a specific dance behind the scenes.

  1. Get Iterator: Python calls iter(collection). This returns an Iterator object.
  2. Request Next: The loop calls next(iterator).
  3. Assign: The returned value is assigned to your loop variable.
  4. Repeat: This continues until the iterator raises a special error called StopIteration.
  5. Clean Exit: The for loop catches StopIteration and terminates gracefully.

This protocol allows for loops to work on anything: lists, strings, files, database cursors, and even infinite streams of data. As long as an object implements __iter__ and __next__, Python can loop over it.


If you need both the item and its position (index), don’t use range(len(list)). Use enumerate.

names = ["Alice", "Bob", "Charlie"]
for index, name in enumerate(names):
print(f"{index}: {name}")

If you have two related lists, zip allows you to traverse them together.

users = ["Alice", "Bob"]
ids = [101, 102]
for name, user_id in zip(users, ids):
print(f"User {name} has ID {user_id}")

Featurefor Loopwhile Loop
Iteration TypeDefinite (fixed number of items)Indefinite (depends on condition)
MechanismIterator Protocol (__next__)Boolean Evaluation
SafetyNo risk of infinite loops (usually)High risk of infinite loops
PerformanceFaster (optimized in C)Slower (manual bytecode evaluation)