Iterating over a list in Python is one of the most common tasks every Python programmer learns, and it is essential for working with collections of data. Day to day, a list is an ordered, mutable collection, which means you can loop through its items, change them, add new values, remove values, or process them one at a time. Whether you are calculating totals, searching for a specific value, transforming data, or printing each item, understanding how to iterate over a list in Python is a core skill Practical, not theoretical..
Introduction to List Iteration
In Python, a list is written using square brackets and can contain almost any type of object:
numbers = [10, 20, 30, 40, 50]
To access each item in the list, you can use several methods, including for loops, while loops, list comprehensions, enumerate(), zip(), and iterator functions such as iter() and next(). Each approach has its own purpose, and choosing the right one can make your code cleaner, faster, and easier to understand Surprisingly effective..
Using a for Loop to Iterate Over a List
The most common way to iterate over a list in Python is with a for loop. A for loop automatically goes through each item in the list one by one.
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
Output:
apple
banana
cherry
In this example, the variable fruit represents one item from the list during each iteration. On top of that, on the first loop, fruit is "apple". On the second loop, it is "banana", and on the third loop, it is "cherry".
This style is preferred when you do not need the position of each item. It is simple, readable, and works well with most lists.
Iterating Over a List with Indexes
Sometimes you need both the item and its position in the list. As an example, you may want to print the item number along with the value. You can use a while loop and an index variable:
colors = ["red", "green", "blue"]
index = 0
while index < len(colors):
print(index, colors[index])
index += 1
Output:
0 red
1 green
2 blue
Here, len(colors) returns the number of items in the list. The loop continues while index is less than the list length. The index starts at 0, which is the first position in a Python list.
Still, this approach is more manual and can be easier to make mistakes with. In most cases, Python provides a better tool for this situation: enumerate() Which is the point..
Using enumerate() for Index and Value
The built-in function enumerate() allows you to loop over a list while also getting the index of each item.
items = ["keyboard", "mouse", "monitor"]
for index, item in enumerate(items):
print(index, item)
Output:
0 keyboard
1 mouse
2 monitor
The enumerate() function returns pairs containing both the index and the value. This is useful when you need to know where an item appears in the list.
You can also start counting from a different number using the second argument:
scores = [85, 90, 78]
for position, score in enumerate(scores, start=1):
print(f"Score {position}: {score}")
Output:
Score 1: 85
Score 2: 90
Score 3: 78
This is especially helpful when displaying results to users, where numbering often starts at 1 instead of 0 That alone is useful..
Iterating Over Multiple Lists with zip()
Python also allows you to iterate over multiple lists at the same time using zip(). This is useful when related pieces of data are stored in separate lists That's the part that actually makes a difference. Less friction, more output..
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 22]
for name, age in zip(names, ages):
print(f"{name} is {age} years old")
Output:
Alice is 25 years old
Bob is 30 years old
Charlie is 22 years old
The zip() function combines the lists into pairs. It stops when the shortest list is exhausted. For example:
names = ["Alice", "Bob", "Charlie"]
scores = [95, 88]
for name, score in zip(names, scores):
print(name, score)
Output:
Alice 95
Bob 88
Even though names has three items, only two pairs are produced because scores has only two items.
Modifying a List While Iterating
You can modify list items while iterating, especially when the list contains mutable objects such as other lists or dictionaries.
prices = [10, 20, 30]
for price in prices:
price *= 2
print(prices)
Output:
[10, 20, 30]
This may look surprising. But the variable price is only a local reference to each item. Multiplying it does not change the original list.
To modify the actual list, use the index:
prices = [10, 20, 30]
for index in range(len(prices)):
prices[index] *= 2
print(prices)
Output:
[20, 40, 60]
This is an important distinction. If you want to replace each item in the list, you usually need to assign a new value using the item’s index.
Adding Items While Iterating
Adding items to a list while iterating can cause unexpected behavior. Python may skip items or continue looping longer than expected because the list is changing while the loop is running.
For example:
items = [1, 2, 3]
for item in items:
items.append(item + 10)
print(items)
This can produce a long or even endless loop depending on the situation, because new items are being added as the loop continues.
A safer approach is to create a new list:
original = [1, 2, 3]
new_items = []
for item in original:
new_items.append(item + 10
)
print(new_items)
Output:
[11, 12, 13]
This approach keeps the original list unchanged and avoids processing newly added items during the same loop Worth keeping that in mind..
Using List Comprehensions
If you're want to transform every item in a list, a list comprehension is often the cleanest option.
original = [1, 2, 3
To further enhance your ability to manipulate collections, consider using the built-in `sorted()` function. This is particularly powerful when working with mixed data structures, such as the paired lists created via `zip()`.
Suppose you have the `names` and `ages` lists and wish to organize them by age instead of their alphabetical order. You can combine them into a single list of tuples and apply the `key` parameter to specify what determines the sort order:
```python
# Pair the data and sort by the second element (the age)
combined = list(zip(names, ages))
sorted_data = sorted(combined, key=lambda x: x[1])
for name, age in sorted_data:
print(f"{name} is {age} years old")
Output:
Bob is 30 years old
Alice is 25 years old
Charlie is 22 years old
Beyond sorting, you
Beyond sorting, you can also take advantage of the sorted function to create a new, ordered view of data without altering the original collection—a useful pattern when you need to preserve the source for later operations. Here's a good example: if you have a list of dictionaries representing products and you want to display them ordered by price while keeping the unsorted list available for inventory updates, you can do:
products = [
{"name": "Widget", "price": 12.99},
{"name": "Gadget", "price": 9.49},
{"name": "Doohickey", "price": 15.00},
]
sorted_by_price = sorted(products, key=lambda p: p["price"])
for item in sorted_by_price:
print(f"{item['name']}: ${item['price']:.2f}")
Because sorted returns a fresh list, the products variable remains unchanged, letting you safely iterate over it elsewhere in the program That's the whole idea..
Another handy technique combines sorted with enumerate when you need both the ordered values and their original positions. Suppose you have a list of scores and you want to rank them, but you also need to know which competitor each score belonged to:
Not obvious, but once you see it — you'll see it everywhere.
scores = [82, 91, 74, 88]
ranked = sorted(enumerate(scores), key=lambda pair: pair[1], reverse=True)
for rank, (idx, score) in enumerate(ranked, start=1):
print(f"Rank {rank}: Competitor {idx} scored {score}")
Here, enumerate pairs each score with its index before sorting, and the final loop restores a human‑readable ranking while preserving the link to the original competitor.
When dealing with nested structures, itemgetter from the operator module can make the key function clearer and slightly faster than a lambda:
from operator import itemgetter
records = [
{"id": 1, "last": "Doe", "first": "John"},
{"id": 2, "last": "Smith", "first": "Jane"},
{"id": 3, "last": "Anderson", "first": "Bob"},
]
sorted_records = sorted(records, key=itemgetter("last", "first"))
for r in sorted_records:
print(r["last"], r["first"])
This sorts first by last name, then by first name, producing a deterministic order without verbose lambda syntax Took long enough..
Finally, remember that Python’s sort is stable: equal keys retain their original relative order. This property enables multi‑stage sorting tricks—sort by a secondary criterion first, then by the primary criterion, and the final list will respect both priorities.
Conclusion
Modifying lists while iterating requires careful use of indices or separate collections to avoid surprises. Adding items during iteration is best handled by building a new list or using structures like deque for efficient appends. For transformations, list comprehensions provide a concise, readable alternative. When ordering data, sorted (along with helpers such as zip, enumerate, and itemgetter) offers a powerful, non‑destructive way to arrange elements according to any criteria you choose. By combining these patterns—index‑based updates, safe accumulation, comprehensions, and thoughtful sorting—you can write Python code that is both expressive and reliable when working with mutable sequences.