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

Параметри й аргументи: сигнатура без сюрпризів

Сигнатура — публічний інтерфейс функції. Вона має зробити обов’язкове неможливо забути, значущі опції — зрозумілими в call site, а небезпечні default values — неможливими. Чим ясніша сигнатура, тим менше прихованих домовленостей у caller-а.

ParametersArgumentsDefaultsKeyword-only

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

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

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

Parameter — ім’я в def, argument — значення у виклику

def route_case(minutes: int, has_blocker: bool) -> str:
    ...

route_case(75, False)
route_case(minutes=75, has_blocker=False)

minutes і has_blocker — parameters. 75 і False — arguments. Positional call короткий, але два сусідні boolean/number values можуть бути неочевидними; keywords роблять call site самодокументованим.

Keyword-only для значущих опцій

def route_case(
    minutes: int,
    *,
    has_blocker: bool = False,
    urgent_at: int = 60,
) -> str:
    ...

route_case(75, has_blocker=True, urgent_at=90)

Маркер * вимагає передавати наступні arguments за іменем. Це корисно для flags, thresholds і units: caller не переплутає True з числом або два thresholds між собою. Не ускладнюйте просту внутрішню функцію без причини; обмеження має покращувати контракт.

Default обчислюється один раз

Default expression виконується під час definition, а не при кожному call. Тому mutable object накопичує стан між викликами.

# Пастка: один list для всіх викликів
def add_label(label: str, labels: list[str] = []) -> list[str]:
    labels.append(label)
    return labels

# Безпечна форма: новий list за потреби
def add_label(label: str, labels: list[str] | None = None) -> list[str]:
    result = [] if labels is None else list(labels)
    result.append(label)
    return result

Копія в другому варіанті ще й не змінює list caller-а. Це окреме контрактне рішення: mutate input чи повернути нове значення.

*args і **kwargs — не заміна дизайну

*args збирає додаткові positional arguments у tuple, **kwargs — keyword arguments у dict. Вони корисні для справді variadic interface або контрольованого forwarding, але прибирають видимість допустимих names. Якщо відомі три поля, назвіть три parameters.

def join_labels(*labels: str, separator: str = ", ") -> str:
    return separator.join(labels)

join_labels("new", "review", separator=" | ")

Type hints допомагають інструментам, не блокують runtime

Annotation minutes: int не забороняє Python передати рядок. Вона покращує editor, static analysis і documentation. На недовіреній межі все одно потрібні conversion і validation; всередині програми можна спиратися на вже перевірений тип.

RequiredБез default; caller мусить передати.
OptionalDefault має чесний domain meaning.
Keyword-onlyNames пояснюють flags, units і thresholds.
VariadicЛише коли кількість input справді змінна.
HintsДокументація й tooling, не runtime firewall.

Матриця тестів для сигнатури

Definition of Done
  • Перевірено мінімальний і повний valid call.
  • Keyword-only option не можна випадково передати позиційно.
  • Окремі виклики не ділять mutable default state.
  • Unknown або duplicate argument дає очікуваний TypeError.
  • Annotations відповідають фактичним return values.

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

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

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

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

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

1. У визначенні def route(minutes, *, has_blocker=False) що означає маркер * перед has_blocker?
2. Чому call route_case(75, True, 90) менш читабельний за keyword-виклик для двох останніх options?
3. Функція def add(label, labels=[]) накопичує елементи між незалежними викликами. Яка причина цієї поведінки?