Вспомогательные алгоритмы и функции в Python
Разбираемся с def, параметрами и return: упаковываем повторяющийся код в функции, вызываем их в цикле и трассируем вызов по шагам на задаче про скидку.
Кнопка «Разогрев» на микроволновке делает за тебя целую цепочку: включила печь, завела таймер на минуту, а по концу — звонок и свет. Один раз инженеры записали эту цепочку внутрь прибора, и теперь каждая кнопка запускает её одной строкой — никто не перепрошивает печь ради обеда. В программе то же самое: def упаковывает блок команд под именем, и после этого одно слово-вызов выполняет их все. Такая упаковка называется функция, а в учебнике информатики — вспомогательный алгоритм: маленький алгоритм внутри большого. Выигрыш двойной: код не копируют десять раз, и правка вносится в одном месте — поменяешь текст приветствия в функции, и все вызовы сразу станут новыми. В математике так же работает формула: записали один раз, подставляешь разные числа. В играх так живёт функция «нанести урон»: она одна, а вызывается на каждый удар каждого персонажа — сотни раз за минуту, и везде один и тот же проверенный код.
def: учим программу новое слово
Объявление выглядит так: def privet(): — слово def, имя, круглые скобки и двоеточие. Дальше с отступом идёт тело: def privet(): print("Здравствуйте!") Всё: функция создана, но ещё не выполнена. Python при чтении def только запоминает, что такое privet, и переходит к следующей строке — так же, как ты, прочитав рецепт, не начинаешь жарить блины. Запускает тело вызов — имя со скобками: privet(). Вызови его трижды — privet() privet() privet() — и трижды увидишь приветствие, а код объявления остался один. Имя для функции придумываешь по тем же правилам, что и имя переменной: латиница, без пробелов, не совпадает со служебными словами. Скобки обязательны: privet без скобок — это не вызов, а просто имя, Python его молча пропустит. Отступ в теле работает так же, как в if и циклах: сдвинул строку не туда — она вылетела из функции, и программа сломается с IndentationError. В теле может быть несколько строк — Python выполнит их сверху вниз, как обычную программу. Хочешь, чтобы privet к тому же возвращала число приветствий, — допиши в конец тела return 3: тело функции устроено по тем же правилам, что и вся программа.
Параметры и return
Функция без данных — как калькулятор без кнопок с цифрами. Данные передают через параметры — переменные в скобках при объявлении: def kvad(x): return x * x Здесь x — параметр: заготовка, в которую при вызове подставится конкретное значение. Вызов kvad(5) вернёт 25, kvad(9) вернёт 81, kvad(0) вернёт 0. Значение при вызове называют аргументом, и подставляются аргументы по порядку: у функции с двумя параметрами первый аргумент уйдёт в первый параметр, второй — во второй. Порядок безразличен, пока операция симметричная: summa(3, 2) и summa(2, 3) вернут одно и то же. Но для f(a, b): return a - b порядок решает всё: f(10, 3) вернёт 7, а f(3, 10) — минус 7. Команда return завершает функцию и отдаёт результат той строке, которая вызвала. Соберём формулу Пифагора: def gipotenuza(a, b): return (a*a + b*b) 0.5** — вызов gipotenuza(3, 4) вернёт 5.0. Ноль на конце не опечатка: возведение в степень 0.5 всегда даёт дробный тип float, даже когда результат круглый. Возвращённое значение сразу живёт в выражениях: kvad(3) + kvad(4) даст 25 — девять плюс шестнадцать, — а запись if kvad(x) > 100: работает в условиях как обычное сравнение. Функция — это почти новая команда языка.
| Вызов | Что подставится | Результат |
|---|---|---|
| kvad(5) | x = 5 | 25 |
| kvad(9) | x = 9 | 81 |
| kvad(0) | x = 0 | 0 |
| summa(2, 3) | a = 2, b = 3 | 5 |
| summa(10, 90) | a = 10, b = 90 | 100 |
| gipotenuza(3, 4) | a = 3, b = 4 | 5.0 |
| privet() | без параметров | печатает Здравствуйте! |
Разбор сложного примера: функция внутри цикла
Соберём всё вместе: функция, цикл и накопитель результата. Программа считает сумму удвоенных чисел от 0 до 3: def dv(x): return x * 2 k = 0 for i in range(4): k = k + dv(i) print(k) Трассируем по кругу. i = 0: вызов dv(0) возвращает 0, в k всё ещё 0. i = 1: dv(1) вернёт 2, k = 0 + 2 = 2. i = 2: dv(2) вернёт 4, k = 6. i = 3: dv(3) вернёт 6, k = 12. Цикл кончился — print печатает 12. Заметь: в k копится не результат одного вызова, а сумма результатов — каждый вызов отдавал своё число, и мы прибавляли его к общему котлу. Такой приём — накопление в цикле через функцию — встречается везде: подсчёт суммы заказов, средней температуры за неделю, общего счёта в игре.
Собираем программу из функций
Смысл функций не в экономии строк, а в порядке: большая задача распадается на шаги с именами, и программа читается как список дел. Магазин считает итог со скидкой: def itog(price, sale): return price - price * sale / 100 print(itog(400, 25)) На экране появится 300.0: скидка 25 процентов от 400 рублей — это 100 рублей, 400 − 100 = 300, а деление добавило дробный хвост. Функции вызывают из других функций и из циклов: for i in range(3): privet() трижды выполнит тело. Цикл умеет копить и результаты: если написать k = 0, а внутри цикла k = k + kvad(i), то после трёх шагов в k окажется 0 + 1 + 4 = 5 — квадраты чисел 0, 1, 2 собрались в сумму. Переменные, созданные внутри функции, — локальные: снаружи их не видно, поэтому имя x в функции не конфликтует с x в основной программе. Именно поэтому большие программы не разваливаются: каждый кусок живёт в своих скобках со своим набором имён. Функции сцепляются в конвейер: сделай chek(price, sale), которая вызывает itog и печатает «К оплате:», — и логика расчёта отделена от его показа на экране: поменял оформление чека — расчёт не тронул, и наоборот. И хороший тон: держи объявления функций в начале файла, выше основного кода, — тогда любой вызов ниже найдёт своё имя.
- Python встречает def itog(price, sale): и запоминает функцию — тело пока не выполнялось ни разу.
- Вызов itog(400, 25): аргументы идут по порядку, в price попадает 400, в sale — 25.
- Тело считает скидку в рублях: 400 * 25 / 100 = 100.0.
- return завершает функцию и отдаёт 400 − 100.0 = 300.0.
- print печатает 300.0: деление в Python всегда даёт дробный тип float, даже если ответ круглый.
- Вызови itog(400, 25) ещё раз — Python повторит весь прогон с начала: функция не помнит прошлых вызовов. А переменные price и sale существуют только во время прогона: вызов завершился — их след простыл.
Как это выглядит в контрольных
Задания на функции в проверочных работах делятся на три вида. Первый — «что выведет программа»: трассируй вызовы на бумажке, как в шагах выше, и следи за порядком аргументов — в f(10, 3) десятка уйдёт в первый параметр, а не во второй. Второй — «найди ошибку»: чаще всего забыли вызвать функцию, потеряли скобки (privet вместо privet()), вернули результат без return или вызвали функцию выше её def. Третий — «напиши функцию»: читай условие как спецификацию — имя, параметры, что возвращать; задача «посчитай площадь прямоугольника» прямо диктует def plosh(a, b): return a * b. Проверяй себя вызовом с простыми числами: plosh(3, 4) обязана вернуть 12, иначе ищи ошибку в теле.
Проверь себя
Клавиши 1–9 выбирают вариант, Enter — «Проверить»
1 Программа: def kvad(x): return x * x; print(kvad(6)). Что выведет программа?
2 Что делает строка def privet():
3 def только описывает функцию: чтобы код в теле заработал, функцию нужно вызвать.
4 Функция объявлена так: def f(a, b): return a + b * 2. Чему равно f(3, 4)? Впиши число.
5 Что вернёт функция, в теле которой нет команды return?
6 Соедини термин с его ролью.
Нажми на элемент слева, затем на его пару справа. Повторное нажатие отменяет связь.
7 Программа: def privet(): print("Привет!"); for i in range(3): privet(). Сколько раз напечатается Привет!?
8 Вставь пропущенное.
Выбери подходящее слово в каждом пропуске.
Ключевое слово объявляет функцию, а команда отдаёт результат той строке, которая вызвала функцию.
Было понятно? Скажи — так мы видим, какие темы переписать.
Частые вопросы
Зачем писать функции, если программа и без них работает?
Без функций повторяющийся код копируют много раз, и править его приходится в каждом месте. Функция хранит блок один раз, а вызывается сколько нужно — программа короче, понятнее и реже ломается.
Чем параметр отличается от аргумента?
Параметр — переменная в скобках при объявлении def, заготовка без значения. Аргумент — конкретное значение, которое подставляется в параметр при вызове.
Что вернёт функция без return?
Специальное значение None. Программа не упадёт, но результат нельзя использовать в вычислениях: print(kvad(5)) напечатает None вместо 25.
Почему Python напечатал 300.0, а не 300?
В формуле было деление на 100, а деление в Python всегда даёт дробный тип float — даже если ответ круглый. Это то же число 300, просто с дробной точкой.