Iterating Python Collections: Lists, Dicts, Sets, Tuples, and Generator Objects
Pythonβs for loop works on anything iterable β lists, tuples, dicts, sets, strings, generators, and custom objects that implement __iter__. The loop mechanics are the same, but each collection type has its own iteration behaviour worth understanding.
Lists and Tuples
Both are ordered sequences. Iteration visits elements left to right.
# Basic iterationfruits = ["apple", "banana", "cherry"]for fruit in fruits: print(fruit)
# With index β use enumerate, not range(len())for index, fruit in enumerate(fruits): print(f"{index}: {fruit}")# 0: apple, 1: banana, 2: cherry
# Custom start indexfor index, fruit in enumerate(fruits, start=1): print(f"{index}: {fruit}")# 1: apple, 2: banana, 3: cherry
# Tuple iteration works identicallycoords = (10, 20, 30)for c in coords: print(c)enumerate is the idiomatic way to get index + value. range(len(lst)) works but is considered un-Pythonic.
Dictionaries
Iterating a dict directly yields keys. Use .values() or .items() for other views.
scores = {"Alice": 92, "Bob": 85, "Carol": 78}
# Iterate keys (default)for name in scores: print(name) # Alice, Bob, Carol
# Iterate valuesfor score in scores.values(): print(score) # 92, 85, 78
# Iterate key-value pairs β most common patternfor name, score in scores.items(): print(f"{name}: {score}")
# Build a new dict while iteratingabove_80 = {k: v for k, v in scores.items() if v > 80}print(above_80) # {'Alice': 92, 'Bob': 85}
# Do not modify the dict while iterating its keys β use a copyto_delete = [k for k, v in scores.items() if v < 90]for key in to_delete: del scores[key]Sets
Sets are unordered β you cannot predict the iteration order, and it is not guaranteed to match insertion order.
unique_tags = {"python", "data", "tutorial", "python", "tips"}print(unique_tags) # {'data', 'python', 'tips', 'tutorial'} β order varies
for tag in unique_tags: print(tag) # some order, not necessarily insertion order
# If you need a consistent order, sort firstfor tag in sorted(unique_tags): print(tag) # alphabetical: data, python, tips, tutorialStrings
Strings are iterable β each iteration step yields one character.
word = "Python"for char in word: print(char) # P, y, t, h, o, n
# Count vowelsvowels = sum(1 for c in word.lower() if c in "aeiou")print(f"Vowels in '{word}': {vowels}")
# Reverse iterationfor char in reversed(word): print(char) # n, o, h, t, y, Pzip β Iterating Multiple Collections Together
names = ["Alice", "Bob", "Carol"]scores = [92, 85, 78]grades = ["A", "B", "C"]
# zip stops at the shortest iterablefor name, score, grade in zip(names, scores, grades): print(f"{name}: {score} ({grade})")
# zip_longest to keep going to the longestfrom itertools import zip_longestlong = [1, 2, 3, 4, 5]short = ["a", "b", "c"]for num, letter in zip_longest(long, short, fillvalue="?"): print(num, letter)# 1 a, 2 b, 3 c, 4 ?, 5 ?Generators β Lazy Iteration
Generators produce values one at a time rather than storing the whole collection in memory. Use them for large data streams.
# Generator expression β like comprehension, but lazygen = (x**2 for x in range(1_000_000)) # nothing computed yet
# Pull values one at a timeprint(next(gen)) # 0print(next(gen)) # 1print(next(gen)) # 4
# Or iterate with for β only one value in memory at a timefor val in (x**2 for x in range(10)): print(val, end=" ")# 0 1 4 9 16 25 36 49 64 81
# Generator functiondef fibonacci_gen(): a, b = 0, 1 while True: yield a a, b = b, a + b
from itertools import isliceprint(list(islice(fibonacci_gen(), 10)))# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]itertools β Advanced Iteration Patterns
from itertools import chain, product, groupby
# chain β iterate multiple iterables as onecombined = chain([1, 2], [3, 4], [5, 6])print(list(combined)) # [1, 2, 3, 4, 5, 6]
# product β cartesian productfor size, colour in product(["S", "M", "L"], ["red", "blue"]): print(f"{size}-{colour}")
# groupby β group consecutive equal elements (input must be sorted by key)data = sorted(["apple", "avocado", "banana", "blueberry", "cherry"], key=lambda x: x[0])for letter, group in groupby(data, key=lambda x: x[0]): print(f"{letter}: {list(group)}")# a: ['apple', 'avocado']# b: ['banana', 'blueberry']# c: ['cherry']Custom Iterable
Any class with __iter__ and __next__ is iterable:
class CountDown: def __init__(self, start): self.current = start
def __iter__(self): return self
def __next__(self): if self.current <= 0: raise StopIteration self.current -= 1 return self.current + 1
for n in CountDown(5): print(n, end=" ")# 5 4 3 2 1The for loop calls __iter__() to get the iterator, then repeatedly calls __next__() until StopIteration is raised.