Quick answer: Python’s for item in iterable syntax is its foreach pattern. Use the value directly when no position is needed, enumerate when an index is part of the result, items for dictionary key-value pairs, zip for parallel iterables, and a generator expression when a transformed stream should remain lazy.

Python does not have a separate foreach keyword. The normal for statement already means “for each item in this iterable,” so it is the direct Python replacement for foreach syntax from languages like PHP, JavaScript, C#, or Java.
The official reference is the Python tutorial section on for statements.
The most Pythonic choice depends on what you need from the loop. Use a plain for loop for side effects, enumerate() when you also need a position, dictionary methods for key-value pairs, list comprehensions for building a new list, and map() when a simple callable should transform every element.
People often search for foreach after using JavaScript Array.forEach(), PHP foreach, or Java enhanced for loops. In Python, the loop target is simply a name bound to the current item. The iterable decides how the next item is produced, and the loop body decides what to do with it.
Do not switch to a while loop just to imitate foreach syntax. A while loop is better for conditions that are not tied to a sequence, such as reading until a sentinel value appears or retrying until a timeout expires.
Use for As Python foreach
A plain for loop reads one item at a time from any iterable object. Lists, tuples, strings, dictionaries, sets, files, and generators all fit this style.
names = ["Ada", "Grace", "Linus"]
for name in names:
print(f"Hello, {name}")
This is the closest Python equivalent to foreach. You do not need a counter when you only care about each item.
Use this form when printing, calling a function, writing rows, updating a report, or performing any action where the result is not meant to be collected into a new list.
For simple loops, choose clear item names. A loop over names should use name; a loop over orders should use order. That keeps the loop readable without extra comments.
Use enumerate For Indexes
When a loop also needs a position, prefer enumerate() over manually increasing a counter. The built-in enumerate() function returns pairs of index and item.
tasks = ["parse", "clean", "export"]
for index, task in enumerate(tasks, start=1):
print(index, task)
The start argument is useful for user-facing numbering, such as menu choices or report lines that should begin at one.
For zero-based positions used by Python data structures, leave start at its default. That keeps list indexing and loop output aligned.
Loop Through Dictionary Items
A dictionary loop can read keys, values, or both. For foreach-style access to both sides, use items().
scores = {"Ada": 98, "Grace": 95, "Linus": 91}
for name, score in scores.items():
print(f"{name}: {score}")
Use scores.keys() when only keys matter and scores.values() when only values matter. In most reporting code, items() is clearer because the pair is shown directly.
Dictionaries preserve insertion order in current Python versions, so iteration follows the order in which items were added.
If you need sorted output, sort the keys or items explicitly. Relying on insertion order is fine for stored order, but sorting makes reports and tests easier to compare.
Build Lists With Comprehensions
If the goal is to create a new list from existing data, a list comprehension is often cleaner than appending inside a loop. The Python docs cover this pattern in list comprehensions.
prices = [10, 25, 40, 80]
discounted = [price * 0.9 for price in prices if price >= 25]
print(discounted)
Use comprehensions for short transformations and filters. If the logic needs many steps, a named function or a regular for loop is easier to debug.
Comprehensions also work for sets and dictionaries, but keep them compact. Dense one-line logic can become hard to read quickly.
Use map For Simple Transformations
map() applies a callable to each item and returns an iterator. It is useful when the transformation already exists as a function.
def normalize(text):
return text.strip().lower()
raw_names = [" Ada ", "GRACE", " linus"]
clean_names = list(map(normalize, raw_names))
print(clean_names)
Many Python developers prefer comprehensions for simple inline expressions because they show the loop shape directly. map() is still clean when the callable has a meaningful name.
Remember that map() is lazy. Wrap it in list() only when you need all results at once.
Break And Continue Still Work
A regular for loop is best when you need break, continue, or a loop-level else clause.
numbers = [3, 7, 12, 19, 24]
for number in numbers:
if number < 10:
continue
if number % 2 == 0:
print("first even value above nine:", number)
break
This style is clearer than forcing control flow into map() or a comprehension. When a loop has decision points, write the decisions visibly.
The practical rule is simple: write for item in iterable for Python foreach behavior. Add enumerate() for positions, items() for dictionaries, comprehensions for new collections, and map() for named transformations.
Also avoid changing a list while looping over that same list. When items need to be removed or transformed, build a new list or iterate over a shallow copy. That prevents skipped items and makes the result easier to reason about.
Iterate Values Directly
A direct for loop is clearer and safer than manually indexing a sequence. It works with lists, tuples, strings, sets, generators, and many custom iterables.
names = ["Ada", "Grace", "Linus"]
for name in names:
print(name)
Use enumerate For Positions
enumerate creates pairs of index and value without range(len(values)). Choose a start index when the displayed numbering should begin somewhere other than zero.
names = ["Ada", "Grace"]
for position, name in enumerate(names, start=1):
print(position, name)
Use items And zip
Dictionary items makes the key-value contract explicit. zip pairs values by position and stops at the shortest iterable unless a different policy is added.
scores = {"Ada": 95, "Grace": 98}
for name, score in scores.items():
print(name, score)
for name, score in zip(["Ada", "Grace"], [95, 98]):
print(name, score)
Keep Transforms Lazy
A generator expression can feed sum, any, all, or another consumer without creating an intermediate list. Materialize it only when the values need to be reused or indexed.
values = [1, 2, 3, 4]
squares = (value * value for value in values)
print(sum(squares))
Python’s for statement, enumerate(), and zip() references define foreach-style iteration. Related references include list iteration, enumerate, and map.
For related iteration patterns, compare list iteration, map, and list lengths when deciding whether an index is needed.
Frequently Asked Questions
Does Python have a foreach keyword?
No. Python’s for item in iterable syntax provides foreach-style iteration.
How do I get an index while iterating?
Use enumerate rather than range(len(values)) when you need both position and value.
How do I loop over a dictionary?
Use keys, values, or items explicitly depending on which part of each entry the code needs.
How do I iterate over two lists together?
Use zip and decide whether unequal lengths should be truncated or rejected.