for Loops
One of the defining features of computers is their ability to perform repetitive tasks with
precision and speed. ๐ Python, like many other languages, offers powerful construct known as
the for loop to automate and simplify such repetitive actions.
What is a for Loop?
A for loop is a programming structure that enables you to execute a specific code block
repeatedly. It iterates over a sequence of items, performing the same actions for each item.
Whether you want to process a list of values, manipulate strings, or iterate over the elements
of a dictionary, the for loop is a go-to tool.
Basic Structure of a For Loop
In Python, a for loop is defined using the for keyword, followed by a variable (often called
an iterator) that represents each item in the sequence, the in keyword, and the sequence itself.
The indented code block immediately following the for statement defines what you want to do with
each item in the sequence.
Would return:
Using For Loops with Lists
See Also
One common use case for for loops is iterating over lists. Lists are collections of data elements,
and you can effortlessly process each element in the list using a for loop. Hereโs an example:
| For Loop Iterating Over a List | |
|---|---|
Results in:
In the above code, the for loop iterates over the fav_books list, converting each book title to
title case and printing it.
For Loops and the range() Function
for loops can also work in tandem with the range() function, which generates a sequence of
numbers. This is particularly useful when you must repeat an action a specific number of times.
However, itโs essential to remember that range() generates numbers up to, but not including
the specified end value. Hereโs an example:
Returns:
This code snippet will print numbers from 1 to 10, emphasizing the importance of being mindful of the common "off by one" error. (We've all been there. ๐ )
Looping Over Dictionaries
See Also
Pythonโs for loop can efficiently iterate over dictionaries
(the dict object)as well. Dictionaries are collections
of key-value pairs, and you can loop over their keys, values, or both. Lets start with a
basic dict of names (keys) and phone numbers (values):
| Basic Dictionary | |
|---|---|
Looping over the keys is the default behaviour, so it is possible to use for
name in phone_numbers:. However, being a bit more explicit is recommended:
| Iterating Over Dictionary Keys | |
|---|---|
It is also possible to loop over the values of a dict object:
| Iterating Over Dictionary Values | |
|---|---|
Which would return:
Depending on the use case, it might also be necessary to return both the keys and the values of
a dict object:
| Iterating Over Dictionary Items (Key and Value) | |
|---|---|
Resulting with:
Tip
Note that dict.items() returns a tuple so we unpack it
by using two variables in the for loop.
Enumerate: Getting Index and Value
A common need is to track both the index and the value while looping. The rookie mistake is to manually manage a counter:
| The Manual Counter (Don't Do This) | |
|---|---|
Python has a better way โ enumerate():
| Using enumerate() | |
|---|---|
Returns:
Starting from a Different Index
By default, enumerate() starts at 0. You can change this with the start parameter:
| enumerate() with Custom Start | |
|---|---|
Returns:
Practical Uses for enumerate()
Zip: Parallel Iteration
When you need to loop over multiple sequences simultaneously, zip() is your friend. It pairs
up elements from each sequence like a zipper bringing two sides together. ๐ค
| Basic zip() | |
|---|---|
Returns:
Zipping Multiple Sequences
zip() isn't limited to two sequences โ add as many as you need:
| Zipping Multiple Sequences | |
|---|---|
Returns:
What Happens with Unequal Lengths?
By default, zip() stops at the shortest sequence:
| Unequal Lengths | |
|---|---|
If you need to process all items (filling in missing values), use itertools.zip_longest:
| zip_longest for Unequal Sequences | |
|---|---|
Returns:
Combining enumerate() and zip()
These tools compose beautifully:
Range Patterns
We've seen basic range(), but it has more tricks up its sleeve.
The Three-Argument Form
range(start, stop, step) gives you full control:
| range() with Step | |
|---|---|
Counting Backwards
Use a negative step to count down:
| Reverse Range | |
|---|---|
Returns:
Common range() Patterns
reversed() vs Negative Step
reversed() is often cleaner than range(len(x)-1, -1, -1). It works on any sequence
and reads more naturally. Use it when you can. โจ
Nested Loops
Loops can contain other loops. Each iteration of the outer loop runs the entire inner loop:
| Nested Loops | |
|---|---|
Returns:
1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
---
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
---
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
---
Practical Nested Loop: Grid Coordinates
| Grid Coordinates | |
|---|---|
Returns:
Nested Loop Performance
Nested loops multiply iterations. A loop of 1000 inside a loop of 1000 = 1,000,000 iterations. Be mindful of performance with large datasets. Sometimes there's a smarter approach. ๐ง
Key Takeaways
| Concept | What to Remember |
|---|---|
| enumerate() | Get index AND value: for i, item in enumerate(list) |
| enumerate(start=1) | Change the starting index |
| zip() | Pair up multiple sequences: for a, b in zip(list1, list2) |
| zip_longest | Handle unequal lengths with itertools.zip_longest |
| range(start, stop, step) | Full control over numeric sequences |
| Negative step | range(10, 0, -1) counts backwards |
| reversed() | Cleaner than negative range for reversing sequences |
| Nested loops | Inner loop runs completely for each outer iteration |