from collections.abc import Callable, MutableSequence from dataclasses import dataclass from enum import Enum, auto from typing import Generic, TypeVar T = TypeVar("T") class ListChange(Enum): ADD_ITEM = auto() REMOVE_ITEM = auto() SET_ITEM = auto() @dataclass(frozen=True) class ListChangeEvent(Generic[T]): index: int @dataclass(frozen=True) class AddItemEvent(ListChangeEvent[T]): item: T @dataclass(frozen=True) class SetItemEvent(ListChangeEvent[T]): item: T @dataclass(frozen=True) class RemoveItemEvent(ListChangeEvent[T]): item: T class HookedList(Generic[T], MutableSequence[T]): elements: list[T] hook: Callable[[ListChangeEvent[T]], None] | None def __init__(self, *args, hook=None, **kwargs): self.elements = list(*args, **kwargs) self.hook = hook def __repr__(self): return f"{self.__class__.__name__}({self.elements!r})" def __iter__(self): return iter(self.elements) def __contains__(self, value): return value in self.elements def __len__(self): return len(self.elements) def __getitem__(self, s): print("Getting item:", s) return self.elements[s] def __setitem__(self, s, value): self.elements[s] = value if self.hook: self.hook(SetItemEvent(index=s, item=value)) def __delitem__(self, s): del self.elements[s] if self.hook: self.hook(RemoveItemEvent(index=s, item=self.elements[s])) def insert(self, index, value): self.elements.insert(index, value) if self.hook: self.hook(AddItemEvent(index=index, item=value))