Python for each in list is a loop construct that executes a block of code once for each element in a list, using the syntax for variable in list:.
This structure is the standard way to traverse a list in Python. It assigns each item in sequence to a variable, then runs the indented code block. The loop ends automatically when all elements have been processed.
For example, for name in ['Alice', 'Bob', 'Charlie']: runs three times, assigning 'Alice', then 'Bob', then 'Charlie' to the variable name.
The for statement in Python iterates over any iterable object, including lists. When the loop begins, Python calls the __iter__() method on the list, which returns an iterator object. That iterator produces one item at a time until exhaustion.
Each iteration assigns the current item to the loop variable. The code block under the for line must be indented. Python uses indentation to define code blocks, not braces or keywords.
After the last item, the loop exits and execution continues with the next line after the block. No explicit counter or index is needed.
The basic form is:
for item in my_list:
# do something with item
Variables used in the loop are local to the block. Reusing the same variable name in nested loops is safe because each loop creates its own scope.
Example:
numbers = [1, 2, 3, 4, 5]
for n in numbers:
print(n * 2)
This outputs:
2
4
6
8
10
Processing data in a list is the most frequent use. You might convert strings to uppercase, filter values, or calculate totals.
To find all even numbers:
nums = [1, 2, 3, 4, 5, 6]
evens = []
for n in nums:
if n % 2 == 0:
evens.append(n)
print(evens) # [2, 4, 6]
Another common pattern is transforming data. For instance, turning a list of names into titles:
names = ['alice', 'bob', 'charlie']
titles = []
for name in names:
titles.append(name.title())
print(titles) # ['Alice', 'Bob', 'Charlie']
While for each in list is often described as a "foreach" loop, Python doesn't use that term. The language uses for with in for all iterables - lists, tuples, sets, dictionaries, strings, and custom objects.
Here's how it behaves across types:
| Type | Iteration Behavior | Example Output |
|---|---|---|
| List | Items in order, by position | [1, 2, 3] → 1, 2, 3 |
| Tuple | Same as list | (a, b) → a, b |
| String | Characters one by one | "abc" → 'a', 'b', 'c' |
| Dictionary | Keys only (unless specified) | {"x": 1} → 'x' |
When iterating over a dictionary, you get keys. To access both key and value, use dict.items():
data = {'a': 1, 'b': 2}
for k, v in data.items():
print(f"{k}: {v}")
Many beginners think they need to track the index manually. But Python provides enumerate() for cases where you need both the index and the value.
Incorrect:
my_list = ['a', 'b', 'c']
i = 0
for item in my_list:
print(i, item)
i += 1
Correct and cleaner:
my_list = ['a', 'b', 'c']
for i, item in enumerate(my_list):
print(i, item)
Using enumerate() avoids off-by-one errors and makes intent clear.
Python's for loop doesn't copy the list. It iterates over the original list object. Modifying the list during iteration can cause unexpected behavior.
Example:
items = [1, 2, 3, 4]
for x in items:
if x % 2 == 0:
items.remove(x) # This skips items!
Removing an item while looping changes the internal state of the list. The iterator advances past the removed element, skipping the next one. This is a known gotcha.
Fix: Iterate over a copy:
items = [1, 2, 3, 4]
for x in items[:]: # slice creates a copy
if x % 2 == 0:
items.remove(x)
This ensures all items are checked.
I once debugged a script that processed log entries. Each entry was a string in a list. The goal was to extract error messages and send them to a monitoring system.
Original code:
logs = [
"INFO: User logged in",
"ERROR: Database connection failed",
"WARNING: Disk space low",
"ERROR: Authentication timeout"
]
errors = []
for log in logs:
if "ERROR" in log:
errors.append(log)
print(errors)
Output:
['ERROR: Database connection failed', 'ERROR: Authentication timeout']
This is clean, readable, and efficient. No indices, no complex logic.
If you need to modify the list while iterating, avoid direct modification. Instead, collect changes and apply them afterward.
For performance-critical code with large datasets, consider list comprehensions or generator expressions. They're faster and more memory-efficient.
Instead of:
result = []
for item in large_list:
if condition(item):
result.append(change(item))
Use:
result = [change(item) for item in large_list if condition(item)]
This is more concise and typically faster.
Python for each in list is the idiomatic way to process every item in a list. It's readable, safe, and widely used in production code. Always prefer it over manual indexing unless you specifically need the index.