Тест самоперевірки

Типи (type hints)

Обери відповідь — і одразу побачиш пояснення. Помилитись тут корисніше, ніж на іспиті.

← до лекції
Відповіді0 / 8   правильних: 0
Питання 1 / 8

Функція оголошена як def сума(кількість: int, ціна: float) -> float. Ти запускаєш сума("кава", 3). Що зробить Python?

Чому так. Анотації під час виконання не перевіряються взагалі. Python бере "кава" * 3, чесно повторює рядок тричі й повертає результат — попри те, що підпис обіцяв float. Спокуслива відповідь про TypeError хибна саме тому, що описує поведінку мов на кшталт Java: у Python перевіряє окремий інструмент, і лише коли ти його запустиш.
Питання 2 / 8

В інтерактиві лекції ти обрав анотацію кількість: Any й виклик сума(None, 85.0). Що покаже mypy і що зробить програма?

Чому так. Any — це не «будь-який тип», а «не дивись сюди»: перевірка в цьому місці вимкнена, тому звіт чистий. Але вимкнена перевірка нічого не лагодить — None * 85.0 усе одно падає. Саме тому Any, поставлений щоб інструмент замовк, — це заклеєна лампочка на панелі приладів.
Питання 3 / 8

У старому коді ти бачиш підпис def знайти(...) -> Optional[Продаж]. Що це означає?

Чому так. Optional[X] — це рівно X | None, ані на крихту не інше. Слово «optional» плутає й натякає на необовʼязковий параметр, хоча йдеться про можливу відсутність значення. Саме через цю плутанину з Python 3.10 пишуть Продаж | None.
Питання 4 / 8

Функція має підпис -> Продаж, але в одній гілці робить return None. Ти запускаєш програму на даних, де потрібний товар завжди знаходиться. Що скаже mypy?

Чому так. Перевірювач читає код як текст і обходить усі гілки одразу — жодних конкретних даних для цього не треба, програма навіть не запускається. Тому він бачить суперечність між обіцянкою -> Продаж і рядком return None. Тест спіймав би те саме, але лише якби хтось здогадався його написати.
Питання 5 / 8

Наш перевірювач із практики скаржиться на виклик сума_позиції(2, 85) — мовляв, у параметр float поїхав int. mypy на цей самий виклик мовчить. Хто має рацію?

Чому так. У правилах перевірки типів є спеціальна поступка: int приймається скрізь, де очікується float, бо в Python ціле майже всюди працює замість дробового. Зворотний напрямок заборонено — 2.5 у параметр int не пройде. Наш isinstance-перевірювач про цю поступку просто не знає.
Питання 6 / 8

Звідки декоратор @dataclass дізнається перелік полів класу?

Чому так. Декоратор читає звичайний словник __annotations__ і перетворює його на __dataclass_fields__ — тобто друге є наслідком першого, а не джерелом. Саме тому рядок без двокрапки полем не стає: він не потрапляє в цей словник, і декоратору не було про що дізнатися.
Питання 7 / 8

У якому рядку анотація дає найменше користі?

Чому так. Тип 0 видно зі значення праворуч від знака рівності — анотація тут повторює те, що вже написано, і додає лише зайвий текст. Три інші рядки додають те, чого в коді немає: порожній список не каже, чого він список; підпис функції перетинає межу між файлами; поле класу з фабрикою теж не показує вмісту.
Питання 8 / 8

Навіщо в модуль додають рядок from __future__ import annotations?

Чому так. За замовчуванням анотація — це вираз, який обчислюється в момент читання def, тому назвати в ній клас, оголошення якого ще не дійшло, не можна. Імпорт із __future__ перетворює анотації на рядки й відкладає їх розбір. Плата: усе, що читає анотації під час виконання, отримує рядки й мусить розвʼязувати їх через typing.get_type_hints().