Guide Python Intermediate

10.19 Hands-on Exercises

Practice programs reinforcing Python list concepts -- an inventory manager class, a todo app, a log analyzer, a CSV processor, and mini projects grouping Amazon EC2 instances and tracking missing Docker containers.

3 min read

Inventory Manager

A small class wrapping a list to manage a collection of items with add/remove/list operations.

class InventoryManager:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

    def remove(self, item):
        if item in self.items:
            self.items.remove(item)

    def list_all(self):
        return self.items

>>> inv = InventoryManager()
>>> inv.add("server01"); inv.add("server02")
>>> inv.remove("server01")
>>> inv.list_all()
['server02']

Todo App

A list of dicts, each representing one task — a common lightweight data model before reaching for a database.

todos = []

def add_todo(task):
    todos.append({"task": task, "done": False})

def complete_todo(index):
    todos[index]["done"] = True

>>> add_todo("Deploy app"); add_todo("Review PR")
>>> complete_todo(0)
>>> todos
[{'task': 'Deploy app', 'done': True}, {'task': 'Review PR', 'done': False}]

Log Analyzer

Counting occurrences of different severity levels across a list of log lines.

def analyze_logs(lines):
    return {
        "errors": sum(1 for l in lines if "ERROR" in l),
        "warnings": sum(1 for l in lines if "WARNING" in l),
    }

>>> analyze_logs(["INFO x", "ERROR y", "WARNING z", "ERROR w"])
{'errors': 2, 'warnings': 1}

CSV Processor

Parsing a CSV blob into a list of dicts, ready for further filtering or aggregation.

import csv, io

def process_csv(text):
    return list(csv.DictReader(io.StringIO(text)))

>>> process_csv("name,age\nAlice,30\nBob,25")
[{'name': 'Alice', 'age': '30'}, {'name': 'Bob', 'age': '25'}]

Mini Projects

Server inventory tool — group a list of Amazon EC2-style instance records by their current state, the core logic behind any fleet-status dashboard:

def group_by_state(instances):
    result = {}
    for inst in instances:
        result.setdefault(inst["state"], []).append(inst["id"])
    return result

>>> group_by_state([
...     {"id": "i-1", "state": "running"},
...     {"id": "i-2", "state": "stopped"},
...     {"id": "i-3", "state": "running"},
... ])
{'running': ['i-1', 'i-3'], 'stopped': ['i-2']}

Docker tracker — combine the container-membership check from 10.15 Lists in DevOps with a list comprehension to report which expected containers are missing from the running list:

expected = ["nginx", "redis", "postgres", "celery"]
running = ["nginx", "redis", "postgres"]
>>> missing = [c for c in expected if c not in running]
>>> missing
['celery']

Backup manager — keep only the N most recent backups, discarding the rest, a common retention-policy script:

def rotate_backups(backups, keep=3):
    return sorted(backups, reverse=True)[:keep]

>>> rotate_backups([
...     "backup_2026-01-01", "backup_2026-01-05",
...     "backup_2026-01-10", "backup_2026-01-15",
... ], keep=2)
['backup_2026-01-15', 'backup_2026-01-10']
  • AWS inventory report — combine the Amazon EC2 filtering pattern from 10.15 Lists in DevOps with the grouping function above to build a full multi-region, multi-state resource report.
  • Kubernetes inventory — combine the pod-filtering pattern from 10.15 Lists in DevOps with count-by-prefix logic to report how many pods each deployment currently has running.

Quick Interview Answer

“These exercises combine the chapter’s tools into small, realistic programs: the inventory manager and todo app wrap a list inside a class or module-level state with add/remove/query operations; the log analyzer and CSV processor lean on comprehensions and the csv module rather than manual parsing; and the mini projects — grouping Amazon EC2 instances by state, diffing expected vs. running Docker containers, rotating backups by keeping the N most recent — are all variations on the same filtering-and-grouping comprehension pattern applied to real infrastructure data.”

Common Mistakes

  • Mutating self.items from outside the InventoryManager class directly instead of going through add()/remove(), bypassing whatever validation those methods might do.
  • Using a list index directly as a todo item’s permanent identifier (complete_todo(index)) — removing an earlier item shifts every later index, silently completing the wrong task.
  • Sorting backup filenames as plain strings and assuming that sorts chronologically — it only works if the naming format is zero-padded and lexicographically ordered the same as chronological order, as in the ISO-style dates used above.

Add More Questions to This Guide

Know a question that should be here? Share it and help the community!

Open Google Form