Модуль 3 · Урок 9 із 58

Функція як контракт: def, return і декомпозиція

Функція корисна не тому, що скорочує файл, а тому, що дає названий контракт: які значення приймає, що повертає, які стани відхиляє і які зовнішні ефекти створює. Такий блок можна перевірити окремо й без здогадок повторно використати.

defreturnКонтрактДекомпозиція

Безпечна практика модуля 3

Пакет містить тільки синтетичні function contracts, import-safe modules і локальні tests. Жодних реальних звернень, персональних даних, secrets, мережевих викликів або зовнішніх залежностей.

Завантажити практичний пакет →

Контракт до коду

Почніть не з def, а з короткої таблиці: input, output, invalid states і side effects. Якщо функція приймає хвилини очікування, треба одразу визначити: це вже int чи ще raw text; чи дозволено від’ємне значення; результат — рядок статусу, число або лише друк.

InputЯкі типи й одиниці надходять у функцію.
OutputЯкий тип та значення отримує caller.
InvalidЯкі стани заборонені й де їх зупиняють.
EffectsЧи функція друкує, пише файл, змінює аргумент або викликає мережу.

Type hint і docstring документують контракт, але самі по собі не забезпечують runtime validation. Перевірка має бути там, де входить недовірене значення.

return передає результат, print лише показує

def classify_wait(minutes: int) -> str:
    """Return a synthetic queue label for validated minutes."""
    if minutes < 0:
        return "invalid"
    if minutes >= 60:
        return "urgent"
    return "standard"

label = classify_wait(75)
print(f"route={label}")

return завершує поточний виклик і передає value caller-у. print() повертає None; він створює display output, але не є результатом бізнес-обчислення. Тому core-функція повертає дані, а CLI-шар вирішує, як їх показати.

Guard clauses зменшують вкладеність

Ранні виходи добре працюють для preconditions і окремих terminal states. Їхній порядок має відповідати пріоритету правил.

def route_case(minutes: int, has_blocker: bool) -> str:
    if minutes < 0:
        return "invalid_minutes"
    if has_blocker:
        return "urgent"
    if minutes >= 60:
        return "expedite"
    return "standard"

Негативний input зупиняється до business rules; blocker має вищий пріоритет за age. Decision table з модуля 2 лишається джерелом прикладів для тесту кожної гілки.

Pure core, imperative shell

Практичний орієнтир — відокремити детерміноване обчислення від I/O. Core отримує готові values і повертає result. Shell читає input, викликає core, друкує output. Це не абсолютне правило, але сильна стартова форма.

CoreБез input(), випадкового часу й прихованого global state.
ShellCLI, файл, мережа або інший boundary; мінімум логіки.
TestВикликає core напряму й порівнює exact result.

Декомпозиція за відповідальністю

Не кожні три рядки потребують функції. Виділяйте блок, коли він має власне ім’я, контракт, повторне використання або окремі приклади для перевірки. Функція process_data() приховує намір; parse_minutes(), route_case() і format_summary() показують pipeline.

Definition of Done
  • Функція має одну зрозумілу відповідальність.
  • Caller використовує return value, а не читає console output.
  • Invalid states і порядок guards задокументовані прикладами.
  • I/O не змішано з обчисленням без потреби.
  • Happy, boundary і invalid cases викликаються повторно.

Методичні джерела

Урок, сценарії, пояснення й вправи створені SEOWORK. Посилання ведуть лише на офіційну документацію Python.

Практична перевірка · урок 9 з 47

Закріпіть матеріал уроку

Три сценарні питання. Для зарахування уроку потрібно дати щонайменше дві правильні відповіді.

1. Функція classify_wait друкує 'urgent', а тест очікує отримати це значення для порівняння. Яку зміну треба зробити?
2. Перед написанням route_case команда хоче зафіксувати перевірний контракт. Який набір полів дає найкращу основу?
3. Чому guard для minutes < 0 має стояти перед business rules, які маршрутизують blocker і threshold?