time.time() помогает измерять длительность, sleep() делает задержку.
collections содержит специализированные структуры данных.
OrderedDict сохраняет порядок и умеет move_to_end().
popitem(last=False) удаляет первый элемент OrderedDict, что удобно для очереди.
Кэш хранит результаты повторных операций, LRU удаляет давно не используемые записи.
@lru_cache кэширует вызовы функции по аргументам.
defaultdict создаёт значение по умолчанию при обращении к отсутствующему ключу.
Counter считает элементы и умеет most_common(), elements(), update(), subtract().
Топ-3 ошибки: использовать sleep() в измерении быстрых операций; забывать, что defaultdict добавляет ключ при чтении; ожидать от Counter вычитания отрицательные значения при операторе -.
Учебный/наивный подход
Современный вариант
Почему так
Проверять if key not in data перед каждым append().
defaultdict(list) для группировки.
Меньше служебного кода и ниже риск KeyError.
Считать частоты вручную через get().
Counter(iterable) и most_common().
Counter выражает намерение напрямую.
Писать свой LRU-кэш для функции.
functools.lru_cache, если аргументы хешируемые.
Стандартная библиотека уже решает типовой сценарий.
Проверить по документации: рекомендации по стилю и стандартной библиотеке могут уточняться в новых версиях Python.