Skip to main content Brad's PyNotes

Control Flow Tools: Mastering If, For, While, and Flow Control

TL;DR

Python’s control flow tools include if/elif/else statements, for and while loops, break/continue statements, and the else clause for loops, providing powerful ways to control program execution.

Interesting!

Python is unique among programming languages in that it uses the else clause with loops - for...else and while...else execute the else block only if the loop completes normally without hitting a break statement.

If Statements and Conditionals

python code snippet start

# Basic if statement
temperature = 25
if temperature > 30:
    print("It's hot!")
elif temperature > 20:
    print("It's warm!")
elif temperature > 10:
    print("It's cool!")
else:
    print("It's cold!")

# Multiple conditions
age = 25
has_license = True

if age >= 18 and has_license:
    print("Can drive")
elif age >= 18:
    print("Can get a license")
else:
    print("Too young to drive")

# Nested if statements
score = 85
grade = ""

if score >= 60:
    if score >= 90:
        grade = "A"
    elif score >= 80:
        grade = "B"
    else:
        grade = "C"
else:
    grade = "F"

print(f"Score: {score}, Grade: {grade}")

python code snippet end

For Loops - Iteration Over Sequences

python code snippet start

# Basic for loop
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(f"I like {fruit}")

# With enumerate for index access
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

# Range-based loops
for i in range(5):
    print(f"Number: {i}")

for i in range(1, 6):  # 1 to 5
    print(f"Number: {i}")

for i in range(0, 10, 2):  # Even numbers 0 to 8
    print(f"Even: {i}")

# Iterating over strings
word = "Python"
for letter in word:
    print(letter)

# Iterating over dictionaries
person = {"name": "Alice", "age": 30, "city": "New York"}

# Keys only
for key in person:
    print(key)

# Key-value pairs
for key, value in person.items():
    print(f"{key}: {value}")

# Values only
for value in person.values():
    print(value)

python code snippet end

While Loops - Condition-Based Iteration

python code snippet start

# Basic while loop
count = 0
while count < 5:
    print(f"Count: {count}")
    count += 1

# User input loop
while True:
    user_input = input("Enter 'quit' to exit: ")
    if user_input.lower() == 'quit':
        break
    print(f"You entered: {user_input}")

# Processing with conditions
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
index = 0
sum_even = 0

while index < len(numbers):
    if numbers[index] % 2 == 0:
        sum_even += numbers[index]
    index += 1

print(f"Sum of even numbers: {sum_even}")

# Fibonacci sequence
a, b = 0, 1
fibonacci = []
while len(fibonacci) < 10:
    fibonacci.append(a)
    a, b = b, a + b

print(f"First 10 Fibonacci numbers: {fibonacci}")

python code snippet end

Break and Continue Statements

python code snippet start

# break - exit loop immediately
for i in range(10):
    if i == 5:
        break
    print(i)  # Prints 0, 1, 2, 3, 4

# continue - skip to next iteration
for i in range(10):
    if i % 2 == 0:
        continue
    print(i)  # Prints 1, 3, 5, 7, 9

# break in nested loops
for i in range(3):
    for j in range(3):
        if i == 1 and j == 1:
            break  # Only breaks inner loop
        print(f"i={i}, j={j}")

# Using flags for breaking nested loops
found = False
for i in range(3):
    for j in range(3):
        if i == 1 and j == 1:
            found = True
            break
    if found:
        break
    print(f"Outer loop: i={i}")

# Or use a function to break from nested loops
def find_item():
    for i in range(3):
        for j in range(3):
            if i == 1 and j == 1:
                return f"Found at ({i}, {j})"
    return "Not found"

result = find_item()
print(result)

python code snippet end

Loop Else Clause

python code snippet start

# for...else - executes if loop completes without break
numbers = [2, 4, 6, 8]
for num in numbers:
    if num % 2 != 0:
        print("Found odd number")
        break
else:
    print("All numbers are even")  # This will execute

# while...else
count = 0
while count < 3:
    print(f"Count: {count}")
    count += 1
else:
    print("Loop completed normally")  # This will execute

# Practical example: searching
def find_prime(n):
    """Find if n is prime using for...else"""
    if n < 2:
        return False
    
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False  # Found a divisor, not prime
    else:
        return True  # Loop completed, no divisors found

print(find_prime(17))  # True
print(find_prime(15))  # False

python code snippet end

Advanced Control Flow Patterns

List Comprehensions with Conditionals

python code snippet start

# Basic list comprehension with condition
numbers = range(10)
evens = [x for x in numbers if x % 2 == 0]
print(evens)  # [0, 2, 4, 6, 8]

# Conditional expression in comprehension
labels = ["even" if x % 2 == 0 else "odd" for x in numbers]
print(labels)

# Nested loops in comprehension
matrix = [[i*j for j in range(3)] for i in range(3)]
print(matrix)  # [[0, 0, 0], [0, 1, 2], [0, 2, 4]]

# Flattening with multiple for clauses
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# Complex filtering
words = ["apple", "banana", "cherry", "date"]
long_words = [word.upper() for word in words if len(word) > 5]
print(long_words)  # ['BANANA', 'CHERRY']

python code snippet end

Exception Handling in Loops

python code snippet start

# Handle exceptions in loops
numbers = ["1", "2", "abc", "4", "xyz"]
converted = []

for num_str in numbers:
    try:
        converted.append(int(num_str))
    except ValueError:
        print(f"Skipping invalid number: {num_str}")
        continue

print(f"Converted numbers: {converted}")

# Using finally in loops
def process_files(filenames):
    for filename in filenames:
        file = None
        try:
            file = open(filename, 'r')
            content = file.read()
            print(f"Processed {filename}: {len(content)} characters")
        except FileNotFoundError:
            print(f"File not found: {filename}")
        finally:
            if file:
                file.close()

# process_files(['file1.txt', 'nonexistent.txt', 'file2.txt'])

python code snippet end

Generator Expressions vs Loops

python code snippet start

# Traditional loop approach
def square_evens_loop(numbers):
    result = []
    for num in numbers:
        if num % 2 == 0:
            result.append(num ** 2)
    return result

# Generator expression approach
def square_evens_gen(numbers):
    return (num ** 2 for num in numbers if num % 2 == 0)

# Usage comparison
numbers = range(10)
loop_result = square_evens_loop(numbers)
gen_result = list(square_evens_gen(numbers))

print(f"Loop result: {loop_result}")
print(f"Generator result: {gen_result}")

python code snippet end

Practical Examples

Data Processing Pipeline

python code snippet start

def process_sales_data(sales_records):
    """Process sales data with control flow"""
    processed_sales = []
    total_revenue = 0
    invalid_records = 0
    
    for record in sales_records:
        # Validate record
        if not isinstance(record, dict):
            invalid_records += 1
            continue
            
        if 'amount' not in record or 'date' not in record:
            invalid_records += 1
            continue
        
        try:
            amount = float(record['amount'])
        except (ValueError, TypeError):
            invalid_records += 1
            continue
        
        # Process valid record
        if amount > 0:
            processed_record = {
                'amount': amount,
                'date': record['date'],
                'category': record.get('category', 'unknown')
            }
            
            # Apply business rules
            if amount > 1000:
                processed_record['priority'] = 'high'
            elif amount > 100:
                processed_record['priority'] = 'medium'
            else:
                processed_record['priority'] = 'low'
            
            processed_sales.append(processed_record)
            total_revenue += amount
        else:
            invalid_records += 1
    
    return {
        'processed_sales': processed_sales,
        'total_revenue': total_revenue,
        'invalid_records': invalid_records,
        'success_rate': len(processed_sales) / len(sales_records) * 100
    }

# Sample data
sales_data = [
    {'amount': '150.50', 'date': '2024-01-01', 'category': 'electronics'},
    {'amount': '2500.00', 'date': '2024-01-02'},
    {'amount': 'invalid', 'date': '2024-01-03'},
    {'amount': '75.25', 'date': '2024-01-04', 'category': 'books'},
]

result = process_sales_data(sales_data)
print(f"Processed {len(result['processed_sales'])} records")
print(f"Total revenue: ${result['total_revenue']:.2f}")
print(f"Success rate: {result['success_rate']:.1f}%")

python code snippet end

python code snippet start

def calculator_menu():
    """Interactive calculator with menu system"""
    
    def add(x, y):
        return x + y
    
    def subtract(x, y):
        return x - y
    
    def multiply(x, y):
        return x * y
    
    def divide(x, y):
        if y == 0:
            raise ValueError("Cannot divide by zero")
        return x / y
    
    operations = {
        '1': ('Addition', add),
        '2': ('Subtraction', subtract),
        '3': ('Multiplication', multiply),
        '4': ('Division', divide)
    }
    
    while True:
        # Display menu
        print("\n=== Calculator ===")
        for key, (name, _) in operations.items():
            print(f"{key}. {name}")
        print("5. Quit")
        
        choice = input("\nSelect operation (1-5): ").strip()
        
        if choice == '5':
            print("Goodbye!")
            break
        
        if choice not in operations:
            print("Invalid choice. Please try again.")
            continue
        
        # Get numbers
        try:
            num1 = float(input("Enter first number: "))
            num2 = float(input("Enter second number: "))
        except ValueError:
            print("Invalid input. Please enter valid numbers.")
            continue
        
        # Perform calculation
        try:
            operation_name, operation_func = operations[choice]
            result = operation_func(num1, num2)
            print(f"\n{operation_name}: {num1} and {num2} = {result}")
        except ValueError as e:
            print(f"Error: {e}")
        except Exception as e:
            print(f"Unexpected error: {e}")

# calculator_menu()  # Uncomment to run interactive menu

python code snippet end

File Processing with Control Flow

python code snippet start

import os

def analyze_text_files(directory):
    """Analyze all text files in a directory"""
    
    if not os.path.exists(directory):
        print(f"Directory {directory} does not exist")
        return
    
    analysis = {
        'files_processed': 0,
        'total_lines': 0,
        'total_words': 0,
        'total_chars': 0,
        'errors': []
    }
    
    # Process each file in directory
    for filename in os.listdir(directory):
        if not filename.endswith('.txt'):
            continue
        
        filepath = os.path.join(directory, filename)
        
        try:
            with open(filepath, 'r', encoding='utf-8') as file:
                line_count = 0
                word_count = 0
                char_count = 0
                
                for line in file:
                    line_count += 1
                    char_count += len(line)
                    
                    # Count words (split on whitespace)
                    words = line.strip().split()
                    word_count += len(words)
                
                # Update totals
                analysis['files_processed'] += 1
                analysis['total_lines'] += line_count
                analysis['total_words'] += word_count
                analysis['total_chars'] += char_count
                
                print(f"Processed {filename}: {line_count} lines, {word_count} words")
                
        except UnicodeDecodeError:
            error_msg = f"Encoding error in {filename}"
            analysis['errors'].append(error_msg)
            print(error_msg)
        except PermissionError:
            error_msg = f"Permission denied for {filename}"
            analysis['errors'].append(error_msg)
            print(error_msg)
        except Exception as e:
            error_msg = f"Error processing {filename}: {str(e)}"
            analysis['errors'].append(error_msg)
            print(error_msg)
    
    # Print summary
    if analysis['files_processed'] > 0:
        avg_lines = analysis['total_lines'] / analysis['files_processed']
        avg_words = analysis['total_words'] / analysis['files_processed']
        
        print(f"\n=== Analysis Summary ===")
        print(f"Files processed: {analysis['files_processed']}")
        print(f"Total lines: {analysis['total_lines']}")
        print(f"Total words: {analysis['total_words']}")
        print(f"Total characters: {analysis['total_chars']}")
        print(f"Average lines per file: {avg_lines:.1f}")
        print(f"Average words per file: {avg_words:.1f}")
        
        if analysis['errors']:
            print(f"\nErrors encountered: {len(analysis['errors'])}")
            for error in analysis['errors']:
                print(f"  - {error}")
    else:
        print("No text files found to process")
    
    return analysis

# Example usage
# result = analyze_text_files('.')

python code snippet end

Performance Tips and Best Practices

python code snippet start

# Use enumerate instead of range(len())
# Bad
items = ['a', 'b', 'c', 'd']
for i in range(len(items)):
    print(f"{i}: {items[i]}")

# Good
for i, item in enumerate(items):
    print(f"{i}: {item}")

# Use zip for parallel iteration
# Bad
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
for i in range(len(names)):
    print(f"{names[i]} is {ages[i]} years old")

# Good
for name, age in zip(names, ages):
    print(f"{name} is {age} years old")

# Use any() and all() for boolean checks
# Bad
has_negative = False
for num in numbers:
    if num < 0:
        has_negative = True
        break

# Good
has_negative = any(num < 0 for num in numbers)

# Bad
all_positive = True
for num in numbers:
    if num <= 0:
        all_positive = False
        break

# Good
all_positive = all(num > 0 for num in numbers)

# Use break and continue to avoid deep nesting
# Bad
for item in items:
    if item.is_valid():
        if item.needs_processing():
            if item.has_permission():
                process_item(item)

# Good
for item in items:
    if not item.is_valid():
        continue
    if not item.needs_processing():
        continue
    if not item.has_permission():
        continue
    
    process_item(item)

python code snippet end

Common Pitfalls and Solutions

python code snippet start

# Pitfall 1: Modifying list while iterating
# Bad - can cause unexpected behavior
numbers = [1, 2, 3, 4, 5]
for num in numbers:
    if num % 2 == 0:
        numbers.remove(num)  # Don't do this!

# Good - iterate over a copy or use list comprehension
numbers = [1, 2, 3, 4, 5]
for num in numbers[:]:  # Iterate over copy
    if num % 2 == 0:
        numbers.remove(num)

# Or better - use list comprehension
numbers = [num for num in numbers if num % 2 != 0]

# Pitfall 2: Variable scope in loops
# Variables defined in loops persist after the loop
for i in range(5):
    x = i * 2

print(x)  # x is still accessible and equals 8

# Pitfall 3: Late binding in loops with lambdas
# Bad
functions = []
for i in range(5):
    functions.append(lambda: i)  # All will return 4!

# Good
functions = []
for i in range(5):
    functions.append(lambda x=i: x)  # Capture current value

# Pitfall 4: Infinite loops
# Always ensure loop variables are modified
count = 0
while count < 10:
    print(count)
    # count += 1  # Don't forget this!

python code snippet end

Control flow tools are fundamental to programming logic, enabling you to create sophisticated programs that respond to different conditions and process data efficiently.

These control flow patterns work exceptionally well with the walrus operator for more expressive code and form the foundation for understanding data structure operations . The patterns shown here integrate with built-in functions and implement Zen of Python principles for readable code. Modern control flow includes pattern matching for sophisticated branching and builds on context management for resource handling.

Reference: Python Tutorial - More Control Flow Tools