Python For Loops: range(), enumerate() and Nested Loops - Python with AI tutorial chapter 19
Python

Python For Loops: range(), enumerate() and Nested Loops

Python with AI Tutorial · Chapter 19 of 48

A Python for loop walks through the items of a sequence one at a time and runs a block of code for each one. It works on lists, tuples, strings, dictionaries and anything else that is iterable. Combined with range(), enumerate() and zip(), the for loop is the workhorse of everyday data processing in Python.

Looping through a list

Write for, a variable name, in and the sequence. The variable takes each value in turn.

regions = ["North", "South", "East", "West"]
for region in regions:
    print(f"Generating report for {region}")
Output:
Generating report for North
Generating report for South
Generating report for East
Generating report for West

Unlike a while loop there is no counter to manage. Python stops automatically when the list runs out.

Anything you can loop over is called an iterable. Lists, tuples, strings, dictionaries, sets, open files and the results of functions such as range() are all iterables, and later in the course you will write your own with generators. The for loop does not care which kind it is given; it simply asks for the next item until there are none left.

Totals and running calculations

A very common pattern is to start an accumulator at zero and add to it inside the loop.

daily_sales = [1250.50, 980.00, 1430.25, 1105.75, 1600.00]
total = 0
for amount in daily_sales:
    total += amount
print(f"Weekly total: {total:,.2f}")
print(f"Average day: {total / len(daily_sales):,.2f}")
Output:
Weekly total: 6,366.50
Average day: 1,273.30

The range() function

range() generates a sequence of integers. It takes a stop value, or start and stop, or start, stop and step. The stop value itself is never included.

Call Produces
range(4) 0, 1, 2, 3
range(1, 5) 1, 2, 3, 4
range(0, 10, 3) 0, 3, 6, 9
range(5, 0, -1) 5, 4, 3, 2, 1
for year in range(2024, 2027):
    print(f"Budget cycle {year}")
for q in range(1, 5):
    print(f"Q{q}", end=" ")
print()
Output:
Budget cycle 2024
Budget cycle 2025
Budget cycle 2026
Q1 Q2 Q3 Q4 

range() does not build the whole list of numbers in memory. It produces each value on demand, so range(10_000_000) costs no more to create than range(10). If you ever need the numbers as an actual list, wrap it in list().

enumerate() for index and value

When you need the position as well as the item, use enumerate(). Pass start=1 to number from one instead of zero.

top_products = ["Laptop Pro", "Desk Lamp", "USB Hub"]
for rank, product in enumerate(top_products, start=1):
    print(f"{rank}. {product}")
Output:
1. Laptop Pro
2. Desk Lamp
3. USB Hub
Try it with AI

Ask the assistant to rewrite an index-based loop with enumerate() and to explain why the enumerate version is considered more Pythonic.

Rewrite this Python loop using enumerate(): for i in range(len(employees)): print(i + 1, employees[i], salaries[i]). Then rewrite it again using zip() so that the two lists are paired without any index at all, and explain when I would choose each version.

zip() to loop over two lists together

zip() pairs up items from two or more sequences so you can process related columns of data side by side.

names = ["Priya", "Tom", "Lena"]
hours = [38, 42, 45]
rate = 25
for name, h in zip(names, hours):
    overtime = max(0, h - 40)
    pay = h * rate + overtime * rate * 0.5
    print(f"{name}: {h}h, pay {pay:.2f}")
Output:
Priya: 38h, pay 950.00
Tom: 42h, pay 1075.00
Lena: 45h, pay 1187.50

If the sequences have different lengths, zip() silently stops at the shortest one, which can hide a data problem. From Python 3.10 you can pass strict=True to make it raise a ValueError instead, a good habit when the lists are supposed to line up, such as names and hours from the same payroll export.

Looping through strings and dictionaries

A string yields one character at a time. A dictionary yields its keys by default, or key-value pairs with .items().

for ch in "SKU":
    print(ch, end="-")
print()

stock = {"chairs": 40, "desks": 12, "monitors": 0}
for item, qty in stock.items():
    status = "out of stock" if qty == 0 else f"{qty} available"
    print(f"{item}: {status}")
Output:
S-K-U-
chairs: 40 available
desks: 12 available
monitors: out of stock

break, continue and else

The same control keywords from the while chapter work in for loops. break exits early, continue skips to the next item and else runs only if the loop was not broken.

payments = [200, 450, 0, 300, 5000, 125]
for p in payments:
    if p == 0:
        continue
    if p > 4000:
        print(f"Flagged for review: {p}")
        break
    print(f"Approved: {p}")
else:
    print("All payments approved")
Output:
Approved: 200
Approved: 450
Approved: 300
Flagged for review: 5000

Read the else as “no break”. In the example the loop was interrupted by the 5,000 payment, so the all-approved message did not appear. Remove that payment from the list and the else block runs.

Nested for loops

A loop inside a loop is useful for grids and combinations. The inner loop runs fully for each item of the outer loop.

branches = ["Mumbai", "Pune"]
quarters = ["Q1", "Q2", "Q3"]
for branch in branches:
    for q in quarters:
        print(f"{branch}-{q}", end="  ")
    print()
Output:
Mumbai-Q1  Mumbai-Q2  Mumbai-Q3  
Pune-Q1  Pune-Q2  Pune-Q3  
Common mistake: never add or remove items from a list while you are looping over it. Python skips or repeats elements unpredictably. Loop over a copy (for x in items[:]) or build a new list instead.

List comprehensions: the compact for loop

When a loop only builds a new list, a comprehension does the same job in one line. The syntax is [expression for item in sequence if condition].

prices = [120, 85, 300, 45]
with_tax = [round(p * 1.18, 2) for p in prices]
expensive = [p for p in prices if p > 100]
print(with_tax)
print(expensive)
Output:
[141.6, 100.3, 354.0, 53.1]
[120, 300]
Try it with AI

Hand the assistant a nested loop and ask it to convert it into a comprehension, then ask which version is easier to read and why.

I have two Python lists: products = ["Chair", "Desk"] and colours = ["Black", "White", "Oak"]. Write a nested for loop that prints every product-colour combination, then rewrite it as a single list comprehension that produces strings like "Chair - Black". Tell me which version you would use in production code and why.

Comprehensions are ideal for a single transformation or filter. Once you need two conditions, a nested loop and a function call in the same line, readability drops fast, so switch back to a normal for loop. A useful rule: if the comprehension does not fit comfortably on one line, it should be a loop.

Common mistakes

  • Assuming range(1, 10) includes 10. The stop value is excluded.
  • Modifying the list you are iterating over, which skips items.
  • Using range(len(items)) when you only need the values; loop over the list directly.
  • Reusing the loop variable name for something else inside the body, which silently overwrites it.
  • Forgetting .items() on a dictionary, so the loop yields only keys.

Exercise

Given invoices = [("INV-01", 500), ("INV-02", 1200), ("INV-03", 75), ("INV-04", 2600)], use a for loop with tuple unpacking to print each invoice number and amount, keep a running total, and after the loop print the total and how many invoices were above 1000.

Show answer
invoices = [("INV-01", 500), ("INV-02", 1200), ("INV-03", 75), ("INV-04", 2600)]
total = 0
large = 0
for number, amount in invoices:
    print(f"{number}: {amount}")
    total += amount
    if amount > 1000:
        large += 1
print(f"Total {total}, {large} invoices above 1000")
Output:
INV-01: 500
INV-02: 1200
INV-03: 75
INV-04: 2600
Total 4375, 2 invoices above 1000

Related chapters

FAQ

How does range() work in a Python for loop?

range(start, stop, step) produces integers from start up to but not including stop. range(5) gives 0 to 4, and a negative step counts downwards.

How do I get the index in a Python for loop?

Wrap the sequence in enumerate(). It yields (index, value) pairs, and enumerate(items, start=1) makes the numbering begin at one.

Can a Python for loop iterate over two lists at once?

Yes. zip(list_a, list_b) pairs the items positionally so you can unpack both values in the loop header. It stops at the shorter list.

Working with spreadsheets too? Ready-made Excel, Google Sheets and Power BI templates are at NextGenTemplates.com.

Chapter 19 of 48 · Python with AI: all 48 chapters

PK
Meet PK, the founder of NeotechNavigators.com! With over 15 years of experience in Data Visualization, Excel Automation, and dashboard creation. PK is a Microsoft Certified Professional who has a passion for all things in Excel. PK loves to explore new and innovative ways to use Excel and is always eager to share his knowledge with others. With an eye for detail and a commitment to excellence, PK has become a go-to expert in the world of Excel. Whether you're looking to create stunning visualizations or streamline your workflow with automation, PK has the skills and expertise to help you succeed. Join the many satisfied clients who have benefited from PK's services and see how he can take your data analysis skills to the next level!
https://neotechnavigators.com