← Маршрут ML-инженерии

Урок · 2 мин чтения · упражнения и самопроверка

Функции

После урока: объяснить аргументы и выполнить упражнение «Исправить изменяемый аргумент по умолчанию», обосновав выбранный подход..

Перед началом

Контракт небольшой операции

Функция объединяет действие с именем и параметрами. Она получает аргументы и возвращает результат через return. print показывает текст человеку, а return передаёт значение вызывающему коду. Функция без явного return возвращает None.

Опишите контракт до реализации: какие значения разрешены, меняет ли функция аргументы и что возвращает. Например, функция суммы списка принимает числа, не меняет список и возвращает число; пустому списку соответствует ноль. Такой контракт легко проверять независимо от чтения ввода.

Имена и изменяемость

Параметры и созданные внутри имена локальны. Если передан список, параметр связывается с тем же объектом: append изменит список вызывающего кода. Переприсваивание параметра другому списку не меняет прежнюю связь имени снаружи. Если изменение не нужно, создайте результат отдельно.

Значение аргумента по умолчанию создаётся при определении функции, а не при каждом вызове. Поэтому items=[] может накопить значения между вызовами. Используйте items=None, затем создавайте список внутри. Сравнивать с None принято через is None.

Декомпозиция

Пусть одна функция вычисляет статистику, другая читает вход, третья оформляет ответ. Тогда вычисление можно тестировать на списке без терминала и файлов. Не создавайте функцию для каждой отдельной строки: выделяйте повторяемые действия или ясные границы ответственности.

В примере два вызова без списка возвращают независимые результаты. Сначала создаётся новый список, затем добавляется значение. Если явно передать существующий список, изменение станет частью контракта; это необходимо объяснить пользователю функции.

Пошаговый пример

python
def add(value, items=None):
    if items is None:
        items = []
    items.append(value)
    return items

print(add(2))
print(add(7))

Ожидаемый вывод

text
[2]
[7]

В каждом вызове с None создаётся новый список. Между вызовами нет накопления.

Сделайте самостоятельно

Напишите count_even(values), которая возвращает число чётных элементов и не меняет список. Проверьте пустой список и [1, 2, 4].

Ответ и критерии проверки

Создайте count = 0, пройдите значения, увеличьте count при value % 2 == 0, затем return count. Ответы 0 и 2. print внутри вычисляющей функции не нужен.

Проверьте понимание

1. Чем return отличается от print?
2. Почему items=[] опасен как значение по умолчанию?