Працюємо з тим самим журналом продажів, що в лекції й практиці. Усі три рівні —
в одному файлі журнал.py, який має запускатися звичайним python3 журнал.py.
Якщо в тебе є можливість поставити перевірювач типів — постав:
pip install mypy
mypy журнал.py
Якщо ні, нічого страшного: кожен рівень має критерій, який перевіряється
assert-ами й друком, без жодних додаткових інструментів.
рівень 1Рівень 1 — База
Опиши свій маленький журнал і анотуй його повністю.
- Створи
@dataclassна свою тему (не продажі): книжки в бібліотеці, треки в плейлисті, витрати за тиждень — що завгодно з чотирма полями, серед яких є хоча б один список. - Напиши дві функції з повними анотаціями параметрів і результату: одну, що рахує число (сума, середнє, кількість), і одну, що повертає список.
- Надрукуй
__annotations__обох функцій і__annotations__свого класу. - Порушь одну анотацію навмисно — передай у параметр
intрядок — і покажиprint-ом, що програма не впала.
Зроблено, якщо: файл запускається без помилок; у виводі видно три словники
анотацій, і в словнику функції є ключ 'return'; є рядок виводу, який доводить,
що виклик із неправильним типом відпрацював без винятку.
рівень 2Рівень 2 — Плюс
Навчися описувати відсутність значення й вкладені структури.
- Напиши функцію пошуку з підписом
-> ТвійКлас | None, яка повертаєNone, коли нічого не знайшла. - Напиши функцію, яка використовує результат пошуку й обробляє обидві гілки
через
if ... is None. Перевірassert-ами обидва випадки: знайшли й не знайшли. - Зроби функцію, яка групує записи у структуру
dict[str, list[ТвійКлас]], і дай цьому типу псевдонім з осмисленим імʼям. - Додай короткий коментар (2–3 речення) про те, що станеться, якщо прибрати
перевірку
is None: яка помилка, у якому рядку й на яких саме даних.
Зроблено, якщо: обидва assert-и проходять; у файлі є рядок-псевдонім типу,
і він використаний хоча б у двох підписах; коментар називає конкретний виняток
(AttributeError) і умову, за якої він виникає.
рівень 3Рівень 3 — Виклик
Доведи власну межу між перевіркою до запуску й перевіркою під час виконання.
- Візьми
перевірити_викликіз практики й навчи його розумітиX | None. Підказка нижче. - Додай другу можливість: якщо анотація — параметризований контейнер
(
list[int],dict[str, int]), перевіряй не лише сам контейнер, а й тип першого елемента. - Склади таблицю з шести-восьми викликів: що каже твій перевірювач і що сказав би mypy (це можна виписати з лекції). Знайди хоча б два випадки, де відповіді розходяться, і поясни кожен одним реченням.
- Заверши висновком: назви одну річ, яку перевірка під час виконання робить краще за mypy, і одну, яку вона не зможе зробити ніколи.
Зроблено, якщо: виклик із None у параметр int | None не дає скарг, а виклик
із рядком у той самий параметр — дає; у таблиці є щонайменше два розходження з
поясненнями; висновок називає конкретні приклади, а не загальні слова.
Підказки
- Дістати складові з
int | Noneможна так:typing.get_origin(анотація)скаже, що це обʼєднання, аtyping.get_args(анотація)поверне кортеж варіантів(int, NoneType). Дляlist[int]ті самі функції дадутьlistі(int,). isinstanceне приймає параметризований тип — це не помилка твого коду, а свідоме обмеження мови. Перевіряй окремо контейнер (get_origin) і окремо елемент.- Порожній контейнер перевірити нічим: у
[]немає першого елемента. Вирішити цю ситуацію можна двома способами — вважати її правильною або скаржитись; обери один і напиши в коментарі, чому саме він. - Не намагайся зробити повноцінний mypy. Мета вправи протилежна: побачити, де саме перевірка під час виконання впирається у стелю.