Exercise 3 solution import heapq import itertools class Scheduler: def __init__(self): self._heap = [] self._counter = itertools.count() self._cancelled = set() def add(self, priority, name): n = next(self._counter) heapq.heappush(self._heap, (priority, n, name)) return n # a ticket for cancel() def cancel(self, ticket): self._cancelled.add(ticket) def next_task(self): while self._heap: priority, n, name = heapq.heappop(self._heap) if n in self._cancelled: self._cancelled.discard(n) continue return name return None s = Scheduler() s.add(2, "write report") s.add(1, "fix outage") t = s.add(3, "tidy desk") s.add(1, "restart server") s.add(2, "send invoice") s.cancel(t) while True: task = s.next_task() if task is None: break print(task) Output: fix outage restart server write report send invoice Lower numbers run first. The counter in the middle of each tuple has two jobs: tasks with equal priority come out in the order they were added ("fix outage" before "restart server"), and Python never has to compare the names. Removing an item from the middle of a heap is awkward, so cancelling is done lazily: the ticket is remembered and the stale entry is simply skipped when it eventually reaches the top. "tidy desk" never appears.