Домашнє завдання

Декоратори

Предметна область тут інша, ніж у лекції, — навмисно: якщо ти зможеш повторити ту саму механіку на своїх даних, значить, справа не в завченому прикладі. Працюємо з бібліотечним каталогом: пошук книжки за шифром, перевірка читацького квитка, статистика звернень. Усе роби в окремому файлі katalog.py або в новому зошиті — практику не редагуй, вона знадобиться для звірки.

Спільна заготовка для всіх трьох рівнів:

import time

КАТАЛОГ = {
    "А-101": "Кобзар",
    "Б-204": "Місто",
    "В-307": "Тигролови",
    "Г-412": "Записки українського самашедшого",
    "Д-518": "Інтернат",
}

def знайти_книгу(шифр):
    """Умовно повільний пошук у каталозі: 30 мс на звернення."""
    time.sleep(0.03)
    return КАТАЛОГ[шифр]

рівень 1Рівень 1 — База

Напиши декоратор @журнал, який записує кожен виклик функції у спільний список, і почепи його на знайти_книгу.

  1. Обгортка має приймати *args, **kwargs і повертати результат незміненим.
  2. У список ЖУРНАЛ клади кортеж (імʼя_функції, аргументи, результат).
  3. Обовʼязково постав @wraps(func).
  4. Зроби дві версії декоратора — з @wraps і без нього — і застосуй їх до двох однакових функцій, щоб порівняти службові поля.

Зроблено, якщо:


рівень 2Рівень 2 — Плюс

Напиши декоратор з аргументом @не_довше(секунд=0.05), який міряє час роботи функції і, якщо вона працювала довше за дозволене, друкує попередження. Результат при цьому має повертатись завжди — декоратор не має права ковтати відповідь.

  1. Три рівні вкладеності: не_довше(секунд)декоратор(func)обгортка(*args, **kwargs).
  2. Перевір його на двох функціях: швидкій (без sleep) і повільній (знайти_книгу зі sleep(0.03)), а також на межі — зроби функцію зі sleep(0.08).
  3. Дай декоратору другий параметр тихо=False: якщо True, попередження не друкується, а лише додається у список ПЕРЕВИЩЕННЯ.
  4. Запиши в коментарі розгортку цього декоратора без синтаксичного цукру — рядком.

Зроблено, якщо:


рівень 3Рівень 3 — Виклик

Напиши власний LRU-кеш і доведи, що він поводиться точно так, як бібліотечний.

  1. Декоратор @мій_lru(maxsize=N): словник аргументи → результат плюс список порядку звернень. При переповненні викидай найдавніше вживаний запис.
  2. Додай метод статистика(), що повертає кортеж (влучань, промахів, розмір) — як cache_info() у бібліотеки.
  3. Візьми послідовність із щонайменше 40 запитів до пʼяти шифрів (склади її сам, з повторами) і прожени її двічі: через свій декоратор і через functools.lru_cache(maxsize=N).
  4. Порівняй hits і misses для maxsize = 1, 2, 3, 5 — усі чотири випадки.
  5. Зміряй час обох варіантів і побудуй табличку «maxsize · влучань · промахів · час».
  6. Додай один випадок, де твій кеш і бібліотечний розійшлися б, якби ти реалізував витіснення неправильно (наприклад, викидав найстаріший доданий, а не найдавніше вживаний), і покажи це числами.

Зроблено, якщо:


Підказки