Python Basics — File Handling Exercises

4 minute read

Practice Exercises — File Handling

Test your understanding of reading files, writing files, context managers, CSV, and JSON.


Exercise 1: Word Counter

Write a function count_words(filename) that reads a text file and returns a dictionary mapping each word (lowercased) to its count. Ignore punctuation.

Test with:

Hello world hello Python
Python is great and hello

Expected output: {'hello': 3, 'world': 1, 'python': 2, 'is': 1, 'great': 1, 'and': 1}

Show Solution
import string

def count_words(filename):
    word_counts = {}
    
    with open(filename, "r") as f:
        for line in f:
            # Remove punctuation and lowercase
            cleaned = line.translate(
                str.maketrans("", "", string.punctuation)
            ).lower()
            
            for word in cleaned.split():
                word_counts[word] = word_counts.get(word, 0) + 1
    
    return word_counts

# Test
counts = count_words("sample.txt")
for word, count in sorted(counts.items()):
    print(f"{word}: {count}")

Exercise 2: CSV Report Generator

Given a list of student dictionaries, write them to a CSV file and then read the file back, calculating the average score.

students = [
    {"name": "Alice", "math": 92, "science": 88, "english": 95},
    {"name": "Bob", "math": 78, "science": 82, "english": 70},
    {"name": "Carol", "math": 95, "science": 91, "english": 89},
    {"name": "Dave", "math": 65, "science": 72, "english": 80},
]

Expected: Write students.csv, read it back, print each student’s average.

Show Solution
import csv

students = [
    {"name": "Alice", "math": 92, "science": 88, "english": 95},
    {"name": "Bob", "math": 78, "science": 82, "english": 70},
    {"name": "Carol", "math": 95, "science": 91, "english": 89},
    {"name": "Dave", "math": 65, "science": 72, "english": 80},
]

# Write to CSV
with open("students.csv", "w", newline="") as f:
    fieldnames = ["name", "math", "science", "english"]
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(students)

print("CSV file written!\n")

# Read back and calculate averages
with open("students.csv", "r") as f:
    reader = csv.DictReader(f)
    
    print(f"{'Name':<10} {'Math':>6} {'Science':>8} {'English':>8} {'Average':>8}")
    print("-" * 44)
    
    for row in reader:
        scores = [int(row["math"]), int(row["science"]), int(row["english"])]
        avg = sum(scores) / len(scores)
        print(f"{row['name']:<10} {row['math']:>6} {row['science']:>8} {row['english']:>8} {avg:>8.1f}")

Exercise 3: JSON Configuration Manager

Create a ConfigManager class that:

  1. Loads settings from a JSON file (or creates defaults if the file doesn’t exist)
  2. Allows getting and setting values
  3. Saves changes back to the file
Show Solution
import json
import os

class ConfigManager:
    DEFAULTS = {
        "theme": "light",
        "language": "en",
        "font_size": 14,
        "auto_save": True,
        "recent_files": [],
    }
    
    def __init__(self, filename="config.json"):
        self.filename = filename
        self.settings = self._load()
    
    def _load(self):
        """Load settings from file, or return defaults."""
        if os.path.exists(self.filename):
            with open(self.filename, "r") as f:
                saved = json.load(f)
            # Merge with defaults (keeps new default keys)
            merged = {**self.DEFAULTS, **saved}
            return merged
        return dict(self.DEFAULTS)
    
    def get(self, key, default=None):
        """Get a setting value."""
        return self.settings.get(key, default)
    
    def set(self, key, value):
        """Set a setting value."""
        self.settings[key] = value
    
    def save(self):
        """Save current settings to file."""
        with open(self.filename, "w") as f:
            json.dump(self.settings, f, indent=4)
    
    def reset(self):
        """Reset to default settings."""
        self.settings = dict(self.DEFAULTS)
        self.save()
    
    def __repr__(self):
        return f"ConfigManager({json.dumps(self.settings, indent=2)})"

# Test
config = ConfigManager("test_config.json")
print(f"Theme: {config.get('theme')}")         # light
print(f"Font size: {config.get('font_size')}")  # 14

config.set("theme", "dark")
config.set("font_size", 16)
config.save()

# Reload and verify
config2 = ConfigManager("test_config.json")
print(f"Theme: {config2.get('theme')}")         # dark
print(f"Font size: {config2.get('font_size')}")  # 16

# Cleanup
os.remove("test_config.json")

Exercise 4: Log File Analyzer

Write a function that reads a log file, extracts entries by severity level (INFO, WARNING, ERROR), and writes a summary report.

Sample log file (app.log):

2025-01-15 10:30:00 INFO Application started
2025-01-15 10:30:05 INFO User login: alice
2025-01-15 10:31:12 WARNING Disk usage at 85%
2025-01-15 10:32:00 ERROR Database connection failed
2025-01-15 10:32:30 INFO Retry successful
2025-01-15 10:35:00 ERROR Timeout on API call
2025-01-15 10:36:00 WARNING Memory usage high
Show Solution
from collections import defaultdict

def analyze_log(input_file, output_file):
    """Analyze log file and write summary report."""
    counts = defaultdict(int)
    entries = defaultdict(list)
    
    with open(input_file, "r") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            
            parts = line.split(maxsplit=3)
            if len(parts) >= 4:
                date, time, level, message = parts
                counts[level] += 1
                entries[level].append(f"  [{date} {time}] {message}")
    
    # Write report
    total = sum(counts.values())
    
    with open(output_file, "w") as f:
        f.write("=" * 50 + "\n")
        f.write("LOG ANALYSIS REPORT\n")
        f.write("=" * 50 + "\n\n")
        
        f.write(f"Total entries: {total}\n\n")
        
        for level in ["ERROR", "WARNING", "INFO"]:
            count = counts.get(level, 0)
            pct = (count / total * 100) if total else 0
            f.write(f"{level}: {count} ({pct:.1f}%)\n")
        
        f.write("\n" + "-" * 50 + "\n")
        f.write("ERRORS:\n")
        for entry in entries.get("ERROR", []):
            f.write(entry + "\n")
        
        f.write("\nWARNINGS:\n")
        for entry in entries.get("WARNING", []):
            f.write(entry + "\n")
    
    print(f"Report written to {output_file}")
    return dict(counts)

# Test
results = analyze_log("app.log", "log_report.txt")
print(f"Summary: {results}")

Exercise 5: File Format Converter (CSV ↔ JSON)

Write two functions:

  1. csv_to_json(csv_file, json_file) — convert a CSV file to a JSON file
  2. json_to_csv(json_file, csv_file) — convert a JSON file (list of objects) to a CSV file
Show Solution
import csv
import json

def csv_to_json(csv_file, json_file):
    """Convert CSV file to JSON file."""
    records = []
    
    with open(csv_file, "r") as f:
        reader = csv.DictReader(f)
        for row in reader:
            records.append(row)
    
    with open(json_file, "w") as f:
        json.dump(records, f, indent=4)
    
    print(f"Converted {len(records)} records: {csv_file} → {json_file}")


def json_to_csv(json_file, csv_file):
    """Convert JSON file (list of objects) to CSV file."""
    with open(json_file, "r") as f:
        records = json.load(f)
    
    if not records:
        print("No records to convert")
        return
    
    # Use keys from first record as fieldnames
    fieldnames = list(records[0].keys())
    
    with open(csv_file, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(records)
    
    print(f"Converted {len(records)} records: {json_file} → {csv_file}")


# Test: Create a CSV, convert to JSON, convert back
test_csv = "test_data.csv"
test_json = "test_data.json"
test_csv_back = "test_data_back.csv"

# Create test CSV
with open(test_csv, "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["name", "age", "city"])
    writer.writerow(["Alice", "30", "NYC"])
    writer.writerow(["Bob", "25", "LA"])
    writer.writerow(["Carol", "35", "Chicago"])

# Convert CSV → JSON
csv_to_json(test_csv, test_json)

# Verify JSON
with open(test_json) as f:
    print(json.dumps(json.load(f), indent=2))

# Convert JSON → CSV
json_to_csv(test_json, test_csv_back)

# Verify CSV
with open(test_csv_back) as f:
    print(f.read())

# Cleanup
import os
for f in [test_csv, test_json, test_csv_back]:
    os.remove(f)

Scoring Guide

Score Level
5/5 Excellent — You handle files like a pro
3-4/5 Good — Solid understanding of file I/O
1-2/5 Keep practicing — Review context managers, CSV, and JSON modules

Next chapter: Error Handling →

Updated: