Programming with Python | Chapter 6: Control Flow – Loops (for, while)

Chapter Objectives

  • Understand the purpose of loops for automating repetitive tasks.
  • Learn to iterate over sequences (lists, tuples, strings) using the for loop.
  • Use the range() function to generate sequences of numbers for for loops.
  • Implement condition-based repetition using the while loop.
  • Control loop execution using break (to exit early) and continue (to skip an iteration).
  • Understand and use the optional else block in loops.
  • Avoid infinite loops.
  • Apply loops to solve common programming problems.

Introduction

In programming, we often need to perform the same or similar actions multiple times. Manually writing the code for each repetition would be tedious and inefficient. Loops provide a powerful mechanism to execute a block of code repeatedly until a certain condition is met or until we have processed all items in a sequence. This chapter introduces Python‘s two main types of loops: the for loop, typically used for iterating over a known sequence of items, and the while loop, used for repeating code as long as a specific condition remains true. We will also cover statements that allow finer control over loop execution: break and continue.

Theory & Explanation

Why Use Loops?

Imagine you need to print each item in a list of 100 names. Without loops, you’d need 100 print() statements. With a loop, you write the print() statement once inside the loop structure, and Python handles the repetition. Loops are fundamental for:

  • Processing items in collections (lists, tuples, strings, dictionaries, sets).
  • Repeating calculations until a condition changes.
  • Reading data from files line by line.
  • Running simulations or animations.
graph TD
    A[Start for loop] --> B{Any items left in sequence?};
    B -- Yes --> C[Assign next item to variable];
    C --> D[Execute Loop Block];
    D --> B; 
    B -- No --> E[Continue after for loop];

The for Loop: Iterating Over Sequences

The for loop is used to iterate over the items of any sequence (like a list, tuple, or string) or any other iterable object, executing a block of code once for each item.

Syntax:

Python
for variable in sequence:
    # Code block to execute for each item (indented)
    # 'variable' takes the value of the current item in each iteration
    statement1
    statement2
# Code here executes after the loop finishes

How it works:

  1. The loop takes the first item from the sequence.
  2. It assigns this item to the variable.
  3. It executes the indented code block using the current value of variable.
  4. It takes the next item from the sequence, assigns it to variable, and executes the block again.
  5. This repeats until all items in the sequence have been processed.
Python
fruits = ["apple", "banana", "cherry"]

print("Processing fruits:")
for fruit in fruits: # 'fruit' takes values "apple", "banana", "cherry" in turn
    print(f"- {fruit.capitalize()}")

print("Loop finished.")

# Iterating over a string
message = "Hello"
for char in message:
    print(char)

The range() Function

Often, you need to loop a specific number of times or iterate over a sequence of numbers. The range() function is perfect for this. It generates a sequence of numbers.

  • range(stop): Generates numbers from 0 up to (but not including) stop.
  • range(start, stop): Generates numbers from start up to (but not including) stop.
  • range(start, stop, step): Generates numbers from start up to (but not including) stop, incrementing by step.
Python
# Print numbers 0 to 4
print("Numbers 0-4:")
for i in range(5):
    print(i)

# Print numbers 2 to 5
print("\nNumbers 2-5:")
for i in range(2, 6):
    print(i)

# Print even numbers from 0 to 8
print("\nEven numbers 0-8:")
for i in range(0, 10, 2):
    print(i)

# Using range to access list elements by index (less Pythonic usually)
numbers = [10, 20, 30]
print("\nAccessing list by index:")
for index in range(len(numbers)): # len(numbers) is 3, range(3) is 0, 1, 2
    print(f"Index {index}: {numbers[index]}")

# More Pythonic way to get index and value: enumerate()
print("\nUsing enumerate():")
for index, value in enumerate(numbers):
    print(f"Index {index}: {value}")

Note: While you can use range(len(sequence)) to loop using indices, iterating directly over the sequence (for item in sequence) or using enumerate() (which yields pairs of (index, value)) is generally preferred as it’s more readable (“Pythonic”).

The while Loop: Condition-Based Repetition

The while loop repeatedly executes a block of code as long as a given boolean condition remains True.

Syntax:

Python
while condition:
    # Code block to execute as long as condition is True (indented)
    statement1
    statement2
    # IMPORTANT: Usually need to update variables involved in the condition
    # to eventually make it False, otherwise -> infinite loop!
# Code here executes after the condition becomes False

How it works:

  1. The condition is evaluated.
  2. If True, the indented code block is executed.
  3. After the block finishes, the condition is evaluated again.
  4. This repeats until the condition evaluates to False.
  5. Execution then continues with the code after the while loop block.
graph TD
    A[Start] --> B{Condition?};
    B -- True --> C[Execute Loop Block];
    C --> B;  
    B -- False --> D[Continue after while];
Python
count = 0
print("Counting up to 3 (using while):")
while count < 3:
    print(f"Count is {count}")
    count += 1 # Crucial step: Modify 'count' so the condition eventually becomes False

print("While loop finished.")

# Example: Waiting for specific input
user_input = ""
while user_input.lower() != "quit":
    user_input = input("Enter command (or 'quit' to exit): ")
    print(f"You entered: {user_input}")

print("Exited program.")

Infinite Loops: If the condition in a while loop never becomes False, the loop will run forever. This usually happens when the variables controlling the condition are not updated correctly within the loop block. You typically need to press Ctrl+C in the terminal to stop an infinite loop.

Loop Control Statements: break and continue

These statements provide more control over loop execution from within the loop block.

1. break

Immediately terminates the entire current loop (both for and while). Execution jumps to the first statement after the loop block.

Python
print("\nFinding first multiple of 3 (using break):")
numbers = [1, 2, 4, 5, 6, 8, 9]
found_multiple = None
for num in numbers:
    print(f"Checking {num}...")
    if num % 3 == 0:
        found_multiple = num
        print(f"Found it! {num}")
        break # Exit the loop immediately
# Code here runs after break or loop completion
if found_multiple:
    print(f"The first multiple of 3 found was {found_multiple}.")
else:
    print("No multiple of 3 found.")

graph TD
    subgraph Loop Block
        direction TB
        L_Start[Start of Loop Iteration] --> Check{Condition for break?};
        Check -- Yes --> Break[break statement];
        Check -- No --> Rest[Execute rest of loop block];
        Rest --> L_End["End of Loop Iteration (continue normally)"];
    end
    Break --> AfterLoop[Execute code immediately after the loop];
    L_End --> LoopCheck[Go to next iteration / Check loop condition];

    style Break fill:#f9f,stroke:#333,stroke-width:2px

2. continue:

Immediately stops the current iteration of the loop and jumps to the next iteration. The rest of the code block for the current iteration is skipped.

Python
print("\nPrinting only odd numbers (using continue):")
for i in range(10): # 0 to 9
    if i % 2 == 0: # If the number is even...
        continue   # ...skip the rest of this iteration and go to the next i
    # This print statement is only reached for odd numbers
    print(i)

graph TD
    subgraph Loop Block
        direction TB
        L_Start[Start of Loop Iteration] --> Check{Condition for continue?};
        Check -- Yes --> Continue[continue statement];
        Check -- No --> Rest[Execute rest of loop block];
        Rest --> L_End[End of Loop Iteration];
    end
    Continue --> LoopCheck[Go immediately to next iteration / Check loop condition];
    L_End --> LoopCheck; 

    style Continue fill:#ccf,stroke:#333,stroke-width:2px

The else Block in Loops

Both for and while loops can have an optional else block. This block is executed only if the loop completes its iterations normally (i.e., not terminated by a break statement).

Syntax:

Python
for item in sequence:
    # Loop body
    if condition_for_break:
        break
else:
    # This block executes ONLY if the loop finished without hitting 'break'
    print("Loop completed normally.")

while condition:
    # Loop body
    if condition_for_break:
        break
else:
    # This block executes ONLY if the loop condition became False (no 'break')
    print("Loop completed normally.")

This is often useful for searching: the else block can run if the item being searched for was not found (because break wasn’t executed).

Python
print("\nSearching for 'kiwi' (using loop else):")
fruits = ["apple", "banana", "cherry"]
search_item = "kiwi"

for fruit in fruits:
    if fruit == search_item:
        print(f"Found {search_item}!")
        break
else:
    # This runs only if the loop finishes without finding 'kiwi'
    print(f"{search_item} not found in the list.")

search_item = "banana"
for fruit in fruits:
    if fruit == search_item:
        print(f"Found {search_item}!")
        break
else:
    print(f"{search_item} not found in the list.") # This line won't run now

graph TD
    A[Start Loop] --> B{Loop Condition / Items Left?};
    B -- True / Yes --> C[Execute Loop Block];
    subgraph Loop Block
        direction TB
        CheckBreak{Break condition met?} -- Yes --> Break[break];
        CheckBreak -- No --> ContinueProcessing[Continue Processing];
    end
    C --> CheckBreak;
    ContinueProcessing --> B; 
    B -- False / No --> ElseBlock[Execute 'else' block];
    Break --> AfterLoop["Continue after loop (skipping else)"];
    ElseBlock --> AfterLoop; 

    style ElseBlock fill:#cfc,stroke:#333,stroke-width:1px

Loop Comparison

Loop Comparison: for vs. while

Feature for Loop while Loop
Primary Use Case Iterating over a sequence (list, tuple, string, range, etc.) or any iterable when the number of iterations is known or determined by the sequence length. Repeating a block of code as long as a specific condition remains true. Often used when the number of iterations is not known beforehand.
Syntax for variable in iterable:
    # code block
while condition:
    # code block
    # update condition variable(s)
Iteration Control Automatically iterates through each item in the iterable. The loop variable takes the value of the current item. Relies on a boolean condition. The condition must be manually managed within the loop (e.g., incrementing a counter, changing a flag) to eventually become false and terminate the loop.
Common Helpers range() for numeric sequences.
enumerate() to get index and value.
Often involves counters or flags initialized before the loop and updated inside.
Risk of Infinite Loop Generally lower risk, as it stops when the iterable is exhausted. (Can happen if iterating over a generator that never stops). Higher risk if the condition is never met or the variables controlling it are not updated correctly within the loop body.
Example Scenario Processing each character in a string.
Applying an operation to every element in a list.
Looping exactly 10 times.
Waiting for user input until ‘quit’ is entered.
Running a simulation until a target state is reached.
Reading from a file until the end is reached.

Both loops can use break to exit early and continue to skip to the next iteration. Both can also have an optional else block.

Code Examples

Example 1: for loop with range and enumerate

Python
# for_loop_examples.py

# Summing numbers from 1 to 10
total = 0
for i in range(1, 11): # 1, 2, ..., 10
    total += i
print(f"Sum of numbers 1 to 10 is: {total}")

# Processing a list with index and value
data = [100, 200, 300, 400]
print("\nProcessing data with enumerate:")
for index, value in enumerate(data):
    print(f"Item at index {index} is {value}. Double is {value * 2}")

# Nested loops to create a multiplication table (up to 3x3)
print("\nMultiplication Table (3x3):")
for row in range(1, 4): # Rows 1, 2, 3
    for col in range(1, 4): # Columns 1, 2, 3
        # print() has an 'end' parameter to control what's printed at the end
        # Default is '\n' (newline), we change it to a tab '\t'
        print(f"{row * col}\t", end="")
    print() # Print a newline after each row is complete

Explanation:

  • The first loop uses range(1, 11) to iterate through numbers 1 to 10 and calculate their sum.
  • The second loop uses enumerate(data) to get both the index and value of items in the data list during iteration.
  • The third example demonstrates nested loops. The outer loop iterates through rows (1 to 3), and the inner loop iterates through columns (1 to 3) for each row. print(..., end="\t") prints the product followed by a tab instead of a newline, keeping items on the same line. The outer print() creates a newline after each row.

Example 2: while loop with break and else

Python
# while_loop_examples.py
import random # Module for generating random numbers

attempts = 0
max_attempts = 5
secret_number = random.randint(1, 10) # Generate a random integer between 1 and 10

print(f"Guess the number between 1 and 10. You have {max_attempts} attempts.")

while attempts < max_attempts:
    guess_str = input(f"Attempt {attempts + 1}: Enter your guess: ")

    # Basic input validation
    if not guess_str.isdigit():
        print("Invalid input. Please enter a number.")
        continue # Skip the rest of this iteration, ask for input again

    guess = int(guess_str)
    attempts += 1

    if guess == secret_number:
        print(f"Congratulations! You guessed the number {secret_number} in {attempts} attempts.")
        break # Exit the loop since the guess is correct
    elif guess < secret_number:
        print("Too low.")
    else:
        print("Too high.")

else:
    # This block runs ONLY if the while loop condition (attempts < max_attempts)
    # becomes False, meaning the loop finished without a 'break'.
    print(f"\nSorry, you've used all {max_attempts} attempts.")
    print(f"The secret number was {secret_number}.")

print("Game over.")

Explanation:

  • A while loop runs as long as attempts is less than max_attempts.
  • Inside the loop, user input is taken.
  • continue is used to skip the rest of the iteration if the input is not a digit.
  • attempts is incremented only after a valid guess.
  • If the guess is correct, a message is printed, and break exits the loop.
  • If the loop completes all attempts without the user guessing correctly (i.e., break was never called), the else block associated with the while loop executes, revealing the number.

while Loop Animation

count = 0 while count < 5: # Update display count += 1 # Loop finished
Count: 0
Press Start to run the loop.

Common Mistakes or Pitfalls

  • Infinite while Loops: Forgetting to update the variable(s) controlling the while loop's condition within the loop body.
  • Off-by-One Errors with range(): Forgetting that range(n) goes up to n-1, or that range(start, stop) does not include stop.
  • Modifying List While Iterating: Modifying a list (e.g., removing items) while iterating over it directly with a for loop can lead to unexpected behavior (skipped items). It's often safer to iterate over a copy (for item in my_list[:]) or use a while loop with indices, or build a new list.
  • Incorrect break/continue Usage: Using break when continue was intended (or vice-versa), or placing them incorrectly, leading to wrong loop termination or skipping logic.
  • Misunderstanding Loop else: Assuming the else block runs if the loop condition is initially false (it doesn't run at all then) or assuming it runs even if break occurred (it doesn't).

Chapter Summary

  • Loops automate repetitive execution of code blocks.
  • The for loop iterates over items in a sequence (list, tuple, string, etc.) or other iterable.
    • Syntax: for variable in sequence:
    • Use range(start, stop, step) to generate numerical sequences.
    • Use enumerate(sequence) to get both index and value.
  • The while loop executes a block as long as a condition is True.
    • Syntax: while condition:
    • Requires careful management of the condition variable(s) inside the loop to avoid infinite loops.
  • break exits the current loop entirely.
  • continue skips the rest of the current iteration and proceeds to the next one.
  • Loops can have an else block that executes only if the loop completes normally (without a break).

Exercises & Mini Projects

Exercises

  1. Countdown: Use a while loop to print numbers from 10 down to 1. After the loop, print "Blast off!".
  2. Factorial Calculator: Ask the user for a non-negative integer. Use a for loop and range() to calculate its factorial (n! = 1 * 2 * 3 * ... * n). Print the result. (Factorial of 0 is 1).
  3. List Summation: Create a list of numbers. Use a for loop to iterate through the list and calculate the sum of all numbers. Print the sum.
  4. Find First Even Number: Create a list of numbers. Use a for loop and break to find and print the first even number in the list. If no even number is found, print a message indicating that. (Hint: Use the loop else block).
  5. Skip Multiples of 3: Use a for loop, range(1, 21), and continue to print all numbers from 1 to 20 except for those that are multiples of 3.

Mini Project: To-Do List Manager (Enhanced)

Goal: Enhance the To-Do List Manager from Chapter 5 using loops for better interaction and display.

Steps:

  1. Start with the code structure from the Chapter 5 Mini Project (initialize tasks = []).
  2. Enclose the main menu logic (displaying options, getting input, if-elif-else for choices) inside a while True: loop. This creates an infinite loop that will keep the program running until the user explicitly chooses to exit.
  3. Modify the Choice 4 (Exit) block:
    • Instead of just printing "Exiting program.", add a break statement. This will terminate the while True: loop and end the program gracefully.
  4. Improve Choice 2 (View Tasks):
    • Instead of just printing the list, use a for loop with enumerate() to print the tasks with their index numbers (starting from 1 for user-friendliness).
    • Example inside the loop: print(f"{index + 1}: {task}")
  5. Improve Choice 3 (Remove Task):
    • After getting the user's input for the index to remove, remember that the user likely entered a 1-based index (like shown in View Tasks), but Python lists use 0-based indexing. Adjust the index accordingly (e.g., actual_index = user_index - 1).
    • Perform the index validation using the actual_index.
    • Use tasks.pop(actual_index) if the index is valid.

Additional Sources:

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top