Iterating Lists, Dictionaries, and Sets in Python: Patterns for Every Collection
Python’s three core collection types — lists, dictionaries, and sets — share the same iteration syntax (for item in collection) but differ significantly in what they expose and what you can rely on. This guide covers the iteration patterns for each, along with the guarantees and limitations that matter in practice.
Lists: Ordered, Indexed, Allows Duplicates
A list preserves insertion order and allows repeated values. Iteration visits elements from index 0 to the end.
Basic Iteration
temperatures = [22.1, 18.5, 25.3, 19.8, 24.0]
for temp in temperatures: print(f"{temp}°C")Index and Value Together: enumerate()
When you need the position as well as the value, enumerate() is cleaner than range(len(...)):
products = ["Laptop", "Mouse", "Keyboard", "Monitor"]
for index, product in enumerate(products, start=1): print(f"{index}. {product}")
# 1. Laptop# 2. Mouse# 3. Keyboard# 4. MonitorPairing Two Lists: zip()
names = ["Alice", "Bob", "Carol"]scores = [91, 84, 88]
for name, score in zip(names, scores): grade = "A" if score >= 90 else "B" print(f"{name}: {score} ({grade})")
# Alice: 91 (A)# Bob: 84 (B)# Carol: 88 (B)zip() stops at the shortest list. If your lists might differ in length, use itertools.zip_longest() with a fillvalue.
Iterating in Reverse
steps = ["Preheat oven", "Mix ingredients", "Pour batter", "Bake", "Cool"]
for step in reversed(steps): print(step)reversed() works on any sequence with a __reversed__ or __len__ and __getitem__. Lists, tuples, and strings all qualify.
Sorted Iteration
countries = ["Germany", "Australia", "France", "Brazil", "India"]
for country in sorted(countries): print(country)
# Australia, Brazil, France, Germany, India
# Sorted descendingfor country in sorted(countries, reverse=True): print(country)sorted() returns a new list — the original is unchanged.
Building Results While Iterating
raw_data = [" Alice ", " 42 ", " Engineering ", " "]
cleaned = [item.strip() for item in raw_data if item.strip()]print(cleaned) # ['Alice', '42', 'Engineering']List comprehensions are the idiomatic way to transform and filter in one pass.
Dictionaries: Key-Value Pairs, Ordered Since Python 3.7
Dictionaries iterate over keys by default, but they expose three views: keys(), values(), and items().
Iterating Keys
config = {"host": "localhost", "port": 5432, "dbname": "myapp", "timeout": 30}
# These are identicalfor key in config: print(key)
for key in config.keys(): print(key)Iterating Values
for value in config.values(): print(value)# localhost, 5432, myapp, 30Iterating Key-Value Pairs (Most Common)
for key, value in config.items(): print(f"{key} = {value}")
# host = localhost# port = 5432# dbname = myapp# timeout = 30This is the most frequently used pattern. The tuple unpacking key, value in the for statement is both concise and explicit.
Conditional Iteration
inventory = { "apples": 0, "bananas": 12, "oranges": 0, "grapes": 30, "mangoes": 7,}
# Items with stockfor product, quantity in inventory.items(): if quantity > 0: print(f"{product}: {quantity} units")
# bananas: 12 units# grapes: 30 units# mangoes: 7 unitsBuilding a Dict From Iteration
words = ["apple", "banana", "cherry", "avocado", "blueberry"]
# Group words by first letterby_letter = {}for word in words: letter = word[0] by_letter.setdefault(letter, []).append(word)
print(by_letter)# {'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}setdefault(key, default) is cleaner than checking if key in dict before appending.
Do Not Modify a Dictionary While Iterating
scores = {"Alice": 88, "Bob": 45, "Carol": 92, "Dave": 51}
# Bug: raises RuntimeError in Python 3for name in scores: if scores[name] < 60: del scores[name] # cannot delete while iterating
# Fix: iterate over a copy of the keysfor name in list(scores.keys()): if scores[name] < 60: del scores[name]
print(scores) # {'Alice': 88, 'Carol': 92}Sets: Unique Elements, No Guaranteed Order
Sets are optimised for membership testing and set operations. Iteration order is not predictable (it depends on hash values and insertion history).
Basic Iteration
tags = {"python", "backend", "data-science", "python", "api"}# Note: duplicate "python" is silently ignored
for tag in tags: print(tag)# Output order is not predictableSorted Iteration Over a Set
When order matters, sort the set first:
for tag in sorted(tags): print(tag)# api, backend, data-science, pythonSet Operations During Iteration
users_online = {"alice", "bob", "carol", "dave"}premium_users = {"bob", "dave", "eve"}
# Who is online AND premium?for user in users_online & premium_users: # intersection print(f"{user} is online and premium")
# Who is online but NOT premium?for user in sorted(users_online - premium_users): # difference print(f"{user} is standard tier")Using Sets to Deduplicate Before Iterating
log_entries = [ "192.168.1.1", "10.0.0.5", "192.168.1.1", "10.0.0.5", "10.0.0.8", "192.168.1.1"]
# Process each IP only oncefor ip in set(log_entries): print(f"Processing {ip}")Choosing the Right Pattern
| Task | Pattern |
|---|---|
| Iterate list values | for item in my_list |
| Index + value | for i, item in enumerate(my_list) |
| Two lists together | for a, b in zip(list1, list2) |
| Dict keys | for key in my_dict |
| Dict values | for val in my_dict.values() |
| Dict key-value pairs | for k, v in my_dict.items() |
| Set (unordered) | for item in my_set |
| Set (sorted) | for item in sorted(my_set) |
| Transform list | [f(x) for x in my_list] |
| Filter list | [x for x in my_list if condition] |
| Reverse list | for item in reversed(my_list) |
Common Pitfalls
Expecting sets to be ordered. They are not. Always sort if order matters.
Modifying a collection while iterating. Iterate over list(collection) or a copy when you need to delete items during the loop.
Using .keys() unnecessarily. for key in my_dict is equivalent to for key in my_dict.keys() — the longer form adds no value.
Assuming zip() handles unequal-length lists. It silently drops the extra items. Use itertools.zip_longest() if you need all items from both lists.