for loops and range()
Computers are good at doing the same thing ten thousand times without getting bored. A loop is how you ask. This is the point where your programs stop being proportional in length to the work they do.
Looping over a sequence
fruits = ["apple", "banana", "mango"]
for fruit in fruits:
print(fruit)
apple
banana
mango
Read it as English: "for each fruit in fruits, print the fruit."
fruit is a name you choose. Python creates it, points it at the first item,
runs the indented block, then re-points it at the next item, and so on until the
sequence is exhausted. You never manage a counter and you can never run off the
end — two entire categories of bug that Python's for loop simply does not
have.
Name the loop variable for what it holds. for f in fruits works; for fruit in fruits reads. The singular-of-the-plural convention is worth following.
Strings are sequences too:
for letter in "Pune":
print(letter)
P
u
n
e
range()
When you want to repeat something a set number of times rather than walk a
collection, range() produces the numbers:
for i in range(5):
print(i)
0
1
2
3
4
Five numbers, starting at zero, ending before five. That exclusive end is
the same rule as string slicing, and holding one mental model for both helps:
range(5) gives you five things.
With two arguments it starts somewhere else:
for i in range(1, 6):
print(i) # 1 2 3 4 5
With three, it steps:
for i in range(0, 101, 10):
print(i) # 0 10 20 ... 100
for i in range(10, 0, -1):
print(i) # 10 9 8 ... 1
That last one counts down. Note the end is 0 and 0 is not printed — the rule
holds even going backwards.
If you genuinely do not need the number, name it _:
for _ in range(3):
print("Hello")
_ is a normal variable name, but by convention it announces "I am ignoring
this", and readers will understand.
enumerate()
Sooner or later you want both the item and its position. The clumsy way:
for i in range(len(fruits)):
print(i, fruits[i])
That works and you will see it in other people's code. The Python way:
for index, fruit in enumerate(fruits):
print(index, fruit)
0 apple
1 banana
2 mango
enumerate hands you both at once. To count from one instead:
for number, fruit in enumerate(fruits, start=1):
print(f"{number}. {fruit}")
1. apple
2. banana
3. mango
Reach for enumerate whenever you catch yourself writing range(len(...)).
The accumulator pattern
This one shape covers an enormous amount of real work: set up a variable before the loop, update it inside, use it after.
prices = [120, 450, 89, 230]
total = 0
for price in prices:
total += price
print(f"Total: {total}")
Total: 889
The critical detail is that total = 0 sits before the loop. Put it inside
and it resets on every pass, leaving you with the last price rather than the
sum. That is a genuinely common bug and the error message will not help you,
because there is no error — just a wrong number.
Counting works the same way:
words = ["python", "is", "a", "good", "language"]
long_words = 0
for word in words:
if len(word) > 3:
long_words += 1
print(f"{long_words} words longer than three letters")
And so does building a new list:
names = ["priya", "arjun", "sneha"]
capitalised = []
for name in names:
capitalised.append(name.title())
print(capitalised)
['Priya', 'Arjun', 'Sneha']
You will write that shape hundreds of times. In the data structures module you will meet a shorter way to say it, but understanding this version first is what makes the short one readable rather than magic.
Finding a maximum
Same pattern, slightly different update:
temperatures = [31, 28, 35, 33, 29]
highest = temperatures[0]
for temperature in temperatures:
if temperature > highest:
highest = temperature
print(f"Highest: {highest}")
Start from the first item, not from zero. Starting at zero happens to work here and fails completely on a list of negative numbers — a bug that hides until winter.
Nested loops
A loop inside a loop. The inner one runs completely for every single pass of the outer one:
for i in range(1, 4):
for j in range(1, 4):
print(f"{i} x {j} = {i * j}")
print("---")
That prints nine lines, with a separator after each group of three.
Nested loops multiply. Two loops of 1,000 items each is a million iterations — fine. Three is a billion, and your program appears to hang. Be aware of what you are nesting.
Looping over a dictionary
You meet dictionaries properly next module, but the loop is worth seeing now:
prices = {"tea": 40, "coffee": 120, "juice": 80}
for item, cost in prices.items():
print(f"{item}: {cost}")
tea: 40
coffee: 120
juice: 80
Two mistakes worth knowing early
Changing a list while looping over it.
numbers = [1, 2, 3, 4, 5, 6]
for number in numbers:
if number % 2 == 0:
numbers.remove(number)
print(numbers)
[1, 3, 5]
That looks right, and it is luck. The loop tracks a position while the list shrinks underneath it, so items get skipped. With a different list it produces visibly wrong results. Build a new list instead of modifying the one you are iterating.
Expecting the loop variable to survive meaningfully.
for i in range(3):
pass
print(i) # 2
It does still exist, holding its last value. Relying on that is fragile — and if
the sequence was empty, the loop never ran and the name never existed, giving
you a NameError at a point far from the cause.
Practice
- Print the numbers 1 to 20, each on its own line.
- Print the 7 times table up to 7 x 10, formatted as
7 x 3 = 21. - Given
prices = [120, 450, 89, 230, 99], use the accumulator pattern to find the total, then the average, then the highest and lowest. - Loop over
"programming"and count how many vowels it contains. - Print a numbered shopping list using
enumerate(..., start=1). - Build a new list containing only the even numbers from
range(1, 21). - Deliberately move the
total = 0line inside the loop from question 3. Run it, see the wrong answer, and explain to yourself exactly why. - Print a 5 x 5 grid of asterisks using nested loops. Then make it a triangle, where row one has one asterisk and row five has five.
Next: while loops, for when you do not know in advance how many times.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship