Loops in Python
Loops are fundamental programming constructs that allow you to execute code repeatedly. They enable you to automate repetitive tasks, process collections of data, and create dynamic behaviors that would be impossible or impractical with simple sequential code.
What are Loops?
Imagine needing to print numbers from 1 to 1000. Without loops, you would need 1000 separate print statements. With loops, you can accomplish this with just a few lines of code. This is the power of iteration in programming.
Types of Loops in Python
Python provides two main types of loops, each designed for different scenarios and use cases.
- While Loop: Repeats code while a condition remains true
- For Loop: Iterates over sequences (lists, strings, ranges) or other iterable objects
# While loop example - condition-based repetition
count = 1
while count <= 5:
print(f"Count: {count}")
count += 1
print("While loop finished!")
# For loop example - iteration over a sequence
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(f"I like {fruit}")
print("For loop finished!")
# For loop with range - number sequences
for number in range(1, 6):
print(f"Number: {number}")
# Comparison: doing the same task with both loops
print("\n=== Counting with while loop ===")
i = 1
while i <= 3:
print(f"While: {i}")
i += 1
print("\n=== Counting with for loop ===")
for i in range(1, 4):
print(f"For: {i}")
# When to use which loop:
# Use WHILE when you don't know how many iterations you need
# Use FOR when you know the sequence or collection to iterate overLoop Control Statements
Loop control statements allow you to change the normal flow of loop execution. They provide fine-grained control over when loops continue, skip iterations, or terminate early.
# break statement - exit the loop immediately
print("=== Break Example ===")
for number in range(1, 10):
if number == 5:
print("Found 5! Breaking out of loop.")
break
print(f"Number: {number}")
print("Loop ended")
# continue statement - skip to the next iteration
print("\n=== Continue Example ===")
for number in range(1, 8):
if number % 2 == 0: # Skip even numbers
continue
print(f"Odd number: {number}")
# Using break and continue together
print("\n=== Finding First Even Number ===")
numbers = [1, 3, 7, 4, 9, 6, 2]
for num in numbers:
if num % 2 != 0: # If odd, skip it
continue
print(f"First even number found: {num}")
break
else:
print("No even number found")
# pass statement - placeholder (does nothing)
print("\n=== Pass Statement ===")
for i in range(3):
if i == 1:
pass # Placeholder - do nothing for now
else:
print(f"Processing: {i}")
# Practical example: validating user input
print("\n=== Input Validation with Loops ===")
valid_choices = ["yes", "no", "maybe"]
user_input = ""
# Note: In real code, you'd use input() here
# This is just for demonstration
sample_inputs = ["invalid", "also invalid", "yes"]
for sample in sample_inputs:
print(f"User entered: {sample}")
if sample.lower() in valid_choices:
user_input = sample
print(f"Valid choice: {user_input}")
break
else:
print("Invalid choice, please try again.")
else:
print("No valid input provided")Common Loop Patterns
Certain loop patterns appear frequently in programming. Understanding these patterns helps you recognize when and how to apply loops effectively in your programs.
# Pattern 1: Accumulator - building up a result
total = 0
numbers = [10, 20, 30, 40, 50]
for num in numbers:
total += num
print(f"Sum: {total}")
# Pattern 2: Counter - counting items that meet criteria
even_count = 0
for num in range(1, 11):
if num % 2 == 0:
even_count += 1
print(f"Even numbers: {even_count}")
# Pattern 3: Finder - searching for specific items
names = ["Alice", "Bob", "Charlie", "Diana"]
search_name = "Charlie"
found = False
for name in names:
if name == search_name:
print(f"Found {search_name}!")
found = True
break
if not found:
print(f"{search_name} not found")
# Pattern 4: Transformer - modifying elements
original_prices = [10.99, 25.50, 8.75, 15.00]
discounted_prices = []
for price in original_prices:
discounted_price = price * 0.9 # 10% discount
discounted_prices.append(discounted_price)
print(f"Original: {original_prices}")
print(f"Discounted: {discounted_prices}")
# Pattern 5: Filter - selecting items that meet criteria
scores = [85, 92, 78, 96, 88, 74, 90]
passing_scores = []
for score in scores:
if score >= 80:
passing_scores.append(score)
print(f"Passing scores: {passing_scores}")
# Pattern 6: Validator - checking all items
valid_emails = True
email_list = ["user@example.com", "admin@site.org", "invalid-email"]
for email in email_list:
if "@" not in email or "." not in email:
print(f"Invalid email: {email}")
valid_emails = False
if valid_emails:
print("All emails are valid")
else:
print("Some emails are invalid")
# Pattern 7: Menu loop - repeat until user chooses to exit
choices = ["1", "2", "3", "4"]
print("\n=== Menu Loop Pattern ===")
for choice in ["1", "2", "invalid", "4"]: # Simulating user input
print(f"User chose: {choice}")
if choice == "1":
print("Processing option 1...")
elif choice == "2":
print("Processing option 2...")
elif choice == "3":
print("Processing option 3...")
elif choice == "4":
print("Exiting...")
break
else:
print("Invalid choice, please try again")
# Pattern 8: Data processing pipeline
raw_data = [" Alice ", "BOB", "charlie", " DIANA "]
processed_names = []
for raw_name in raw_data:
# Clean and format the name
clean_name = raw_name.strip().title()
processed_names.append(clean_name)
print(f"Processed names: {processed_names}")The “accumulator pattern” is one of the most fundamental programming patterns. You'll use it constantly for summing, counting, building strings, collecting results, and many other tasks. Master this pattern, and you'll solve countless programming problems!
Nested Loops
Nested loops are loops inside other loops. They're essential for processing multi-dimensional data, creating patterns, and solving complex problems that require multiple levels of iteration.
# Basic nested loop structure
print("=== Basic Nested Loops ===")
for i in range(1, 4):
print(f"Outer loop: {i}")
for j in range(1, 3):
print(f" Inner loop: {j}")
print() # Empty line for clarity
# Multiplication table
print("=== Multiplication Table ===")
for i in range(1, 6):
for j in range(1, 6):
product = i * j
print(f"{product:2}", end=" ")
print() # New line after each row
# Processing 2D data structure
print("\n=== Processing 2D Data ===")
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Find sum of all elements
total = 0
for row in matrix:
for element in row:
total += element
print(f"Sum of all elements: {total}")
# Find maximum element
max_element = matrix[0][0] # Start with first element
for row in matrix:
for element in row:
if element > max_element:
max_element = element
print(f"Maximum element: {max_element}")
# Creating patterns with nested loops
print("\n=== Star Patterns ===")
# Right triangle pattern
for i in range(1, 6):
for j in range(i):
print("*", end="")
print()
print() # Separator
# Rectangle pattern
for i in range(4):
for j in range(6):
print("*", end="")
print()
print() # Separator
# Number pattern
for i in range(1, 5):
for j in range(1, i + 1):
print(j, end="")
print()
# Real-world example: Student grade processing
print("\n=== Student Grade Processing ===")
students = {
"Alice": [85, 92, 78, 96],
"Bob": [88, 84, 90, 87],
"Charlie": [92, 89, 94, 91]
}
for student_name, grades in students.items():
total_points = 0
for grade in grades:
total_points += grade
average = total_points / len(grades)
print(f"{student_name}: Average = {average:.1f}")
# Searching in 2D structure
print("\n=== Finding Item in 2D List ===")
classroom = [
["Alice", "Bob", "Charlie"],
["Diana", "Eve", "Frank"],
["Grace", "Henry", "Iris"]
]
search_student = "Eve"
found_position = None
for row_index, row in enumerate(classroom):
for col_index, student in enumerate(row):
if student == search_student:
found_position = (row_index, col_index)
break
if found_position:
break
if found_position:
print(f"{search_student} found at row {found_position[0]}, column {found_position[1]}")
else:
print(f"{search_student} not found")
# Nested loop with conditions and breaks
print("\n=== Complex Nested Loop Example ===")
numbers = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
target = 5
for i, row in enumerate(numbers):
for j, num in enumerate(row):
if num == target:
print(f"Found {target} at position ({i}, {j})")
break
else:
continue # Continue outer loop if inner loop completed normally
break # Break outer loop if inner loop was brokenBest Practices
Following best practices when writing loops makes your code more readable, efficient, and maintainable. These guidelines will help you write professional-quality loops.
- Choose the right loop type: Use for loops for known sequences, while loops for unknown iterations
- Use descriptive variable names: Avoid single letters like 'i' unless the context is very clear
- Avoid infinite loops: Ensure loop conditions will eventually become false
- Keep loop bodies simple: Extract complex logic into functions
- Use enumerate() for index access: Better than manual counter variables
- Consider list comprehensions: For simple transformations and filters
# Best Practice 1: Descriptive variable names
# Bad
for i in ["apple", "banana", "cherry"]:
print(i)
# Good
for fruit in ["apple", "banana", "cherry"]:
print(fruit)
# Best Practice 2: Use enumerate() for index access
# Bad
fruits = ["apple", "banana", "cherry"]
index = 0
for fruit in fruits:
print(f"{index}: {fruit}")
index += 1
# Good
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# Best Practice 3: Avoid manual index management
# Bad
items = ["a", "b", "c", "d"]
i = 0
while i < len(items):
print(items[i])
i += 1
# Good
for item in items:
print(item)
# Best Practice 4: Use zip() for parallel iteration
# Bad
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
for i in range(len(names)):
print(f"{names[i]}: {scores[i]}")
# Good
for name, score in zip(names, scores):
print(f"{name}: {score}")
# Best Practice 5: Extract complex logic into functions
def process_student_data(student_name, grades):
"""Process individual student data."""
if not grades:
return f"{student_name}: No grades available"
average = sum(grades) / len(grades)
letter_grade = "A" if average >= 90 else "B" if average >= 80 else "C"
return f"{student_name}: {average:.1f} ({letter_grade})"
# Clean loop using the helper function
students_data = {
"Alice": [85, 92, 78, 96],
"Bob": [88, 84, 90, 87],
"Charlie": []
}
for student, grades in students_data.items():
result = process_student_data(student, grades)
print(result)
# Best Practice 6: Use list comprehensions when appropriate
# Traditional loop
squared_numbers = []
for num in range(1, 6):
squared_numbers.append(num ** 2)
# List comprehension (more Pythonic)
squared_numbers = [num ** 2 for num in range(1, 6)]
print(f"Squared numbers: {squared_numbers}")
# Best Practice 7: Handle edge cases
def safe_division(numbers, divisor):
"""Safely divide a list of numbers."""
if divisor == 0:
return "Cannot divide by zero"
results = []
for num in numbers:
results.append(num / divisor)
return results
numbers = [10, 20, 30]
print(f"Division results: {safe_division(numbers, 2)}")
print(f"Division by zero: {safe_division(numbers, 0)}")
# Best Practice 8: Use break and continue wisely
def find_first_positive(numbers):
"""Find the first positive number in a list."""
for num in numbers:
if num <= 0:
continue # Skip non-positive numbers
return num # Return immediately when found
return None # No positive number found
test_numbers = [-5, -2, 0, 3, 7]
result = find_first_positive(test_numbers)
print(f"First positive number: {result}")
# Best Practice 9: Avoid modifying lists while iterating
# Bad - can cause issues
items = [1, 2, 3, 4, 5]
# Don't do this: for item in items: items.remove(item)
# Good - iterate over a copy or use list comprehension
items = [1, 2, 3, 4, 5]
items = [item for item in items if item % 2 == 0] # Keep even numbers
print(f"Even items: {items}")
# Best Practice 10: Use appropriate data structures
# If you need to check membership frequently, use a set
valid_codes = {"ABC", "DEF", "GHI", "JKL"} # Set for fast lookup
input_codes = ["ABC", "XYZ", "DEF", "QRS"]
for code in input_codes:
if code in valid_codes: # Fast O(1) lookup
print(f"{code}: Valid")
else:
print(f"{code}: Invalid")Loops are essential tools that you'll use in almost every Python program. They enable you to process data efficiently, automate repetitive tasks, and build dynamic applications. Understanding when and how to use different types of loops will make you a more effective programmer and open up countless possibilities for solving problems with code.