Функции и аргументы
В тетради стоят три строки подряд, почти одинаковые:
- print(100 / 1.609344)
- print(42 / 1.609344)
- print(7.5 / 1.609344)
Ученик пересчитывал километры в мили, и в каждой следующей строке правил одно число. Копировать строку в третий раз неловко: рука уже знает, что сейчас придётся заменить сотню на сорок два, и именно здесь стоит остановиться. Если вы замечаете, что в программе появился повторяющийся кусок и вам от этого немного не по себе, чувство верное, и функции придуманы как раз для него.
Посмотрите на них внимательно. Действие одно и то же: взять число и разделить на 1,609344. Меняется только само число. Из этого наблюдения вытекает всё остальное: то, что меняется, становится параметром, а то, что остаётся прежним, прячется внутрь.
Здесь и проходит граница между функцией и записью «как придётся». Функция — это действие, которому дали имя и оставили в нём пробел для переменной части. Само вычисление, деление на 1,609344, пишется один раз и лежит в одном месте. Когда окажется, что коэффициент в тетради записан с ошибкой, исправлять придётся одну строку, а не сорок.
Дальше предполагается, что строку с вычислением вы уже писали. Если нет, начните со статьи о порядке тем школьного курса: функции там стоят не первыми.
Первая функция
В Python она выглядит так (тело здесь записано в одну строку):
- def km_v_mili(km): return km / 1.609344
Если запустить файл, где есть только эта строка, на экране не появится ничего: определение лишь объясняет Python, что значит km_v_mili, а вызывать функцию он не станет. Жалоба «программа ничего не делает» в первые недели нередко сводится к забытому вызову. Теперь три исходные строки превращаются в три вызова:
- print(km_v_mili(100))
- print(km_v_mili(42))
- print(km_v_mili(7.5))
Строк стало даже на одну больше, так что выигрыш не в длине. Вызов читается как фраза: «километры в мили от ста». Имя тоже часть работы: km_v_mili сообщает, что функция делает, а f1 заставляет каждый раз заглядывать внутрь. Забытый коэффициент перестал быть загадкой, потому что у него появилось имя, а вызов больше не зависит от того, как именно устроено деление.
Мили, к слову, взяты не случайно: одна миля равна ровно 1,609344 километра, и это число не округляют. Если в вашей программе стоит 1,6 или 1,61, ответы совпадут с проверочными лишь приблизительно.
Выигрыш от единого места заметнее всего при правке. Пусть выяснилось, что в пересчёт попадают отрицательные расстояния, а они бессмысленны, и программа должна в этом случае вернуть None. Правится одна строка: def km_v_mili(km): return None if km < 0 else km / 1.609344. Остальные сорок мест, где функция вызывается, остаются как были (None здесь выбран намеренно, как знак «пересчёта нет»). Когда деление записано в сорока местах, найти и поправить придётся каждое, а пропущенное место проявится позже и совсем в другом виде.
Параметр и аргумент
В определении функции стоит km — это параметр, название пустого места. В вызове стоят 100, 42, 7.5 — это аргументы, то, что в пустое место подставляется. Слов два, и путают их все. Различать их приходится в одном случае: когда читаешь сообщение об ошибке. Оно говорит про «аргументы», если вы передали не столько значений, сколько функция ждёт, например ничего или сразу два числа вместо одного.
У функции бывает несколько параметров. Для градусов Цельсия и Фаренгейта пригодится функция с тремя: что пересчитывать, на сколько умножить и сколько прибавить.
- def linear(x, k, b): return x * k + b
- print(linear(36.6, 1.8, 32))
- print(linear(100, 1 / 1.609344, 0))
Первый вызов печатает температуру тела по Фаренгейту, второй снова даёт мили. Одна функция обслуживает два пересчёта, потому что оба устроены как «умножить и прибавить». Это следующая ступень: сначала повторяются строки, потом замечаешь, что повторяются целые функции, и обобщаешь их. Задерживаться на этой ступени необязательно.
Одна оговорка про первый вызов: он напечатает 97.88000000000001 вместо аккуратных 97.88. Дробные числа хранятся в двоичном виде, и небольшой хвост неизбежен (о типах данных рассказано в статье про переменные и типы). Оборачивайте результат в round, как в примере ниже, и хвоста не будет.
Параметру можно дать значение по умолчанию, и тогда аргумент в вызове можно не писать. Пусть функция округляет результат, а число знаков по умолчанию равно двум: def km_v_mili(km, znakov=2): return round(km / 1.609344, znakov). Вызов km_v_mili(100) даст 62.14, а km_v_mili(100, 4) — 62.1371. Параметры со значениями по умолчанию пишут в конце списка, иначе Python сообщит о синтаксической ошибке.
Что выходит из функции и как это проверить
Переменная, заведённая в теле функции, после вызова снаружи не видна. Проверьте: функция def km_v_mili(km): m = km / 1.609344; return m работает как раньше, а print(m) после неё падает с ошибкой «name m is not defined». Новичков это обычно сначала раздражает: значение же только что посчитано. Но именно так функция не мешает остальной программе: внутри можно называть переменные как угодно и не бояться, что одно из имён совпадёт с чужим снаружи.
Все данные, которые должны выйти наружу, уходят через return; про глобальные переменные, которые функция всё же умеет менять, пока можно не думать, потому что они чаще вредят, чем помогают. Есть и порядок записи: функцию нужно определить раньше, чем вызвать. Если вызов стоит в файле выше определения, Python сообщит, что такого имени ещё нет, и ошибка в этом месте у новичков встречается на удивление часто.
Самая частая ошибка в первой функции: вместо return пишут print.
- def km_v_mili(km): print(km / 1.609344)
- x = km_v_mili(10) + 5
Первая строка выглядит рабочей: вызываете функцию, число появляется на экране. Вторая падает, потому что функция ничего не вернула (в Python в этом случае результат — специальное значение None), и складывать с пятёркой нечего. Print показывает результат человеку, return отдаёт его программе. Для функции, которую будут вызывать из другой функции, нужен return почти всегда; print уместен там, где функция единственная и стоит в самом конце.
Проверка годится для любой своей функции: подставьте вызов в выражение, например в сумму или в сравнение. Выражение работает, значит, функция возвращает значение. Появилось None или сообщение об ошибке при сложении, значит, внутри стоит print.
У пересчёта единиц есть удобная проверка, которой нет у большинства задач: ответ можно получить двумя путями. Нуль километров должен дать нуль миль. Ровно 1,609344 километра должны дать ровно одну милю (с точностью до хвоста в последних знаках). А ещё напишите обратную функцию, mili_v_km, и пропустите число через обе: mili_v_km(km_v_mili(42)) должно вернуть почти те же сорок два. Если не вернуло, коэффициент в одной из функций перепутан или стоит не там, где нужно.
Привычка проверять функцию двумя-тремя вызовами с заранее известным ответом отнимает минуту, и именно она отличает написанное от проверенного. Известный ответ нужно придумать до запуска, иначе проверка превращается в разглядывание того, что напечатала программа: любое число выглядит правдоподобно.
Когда нужен цикл, а когда функция
Три одинаковые строки легко принять за повод для цикла, и это частая путаница. Цикл повторяет действие над значениями, которые лежат рядом: если сто, сорок два и семь с половиной уже собраны в список, цикл по списку справится (циклы и списки разобраны в отдельных статьях). Функция нужна, когда одно действие требуется в разных местах программы, а значения в него приходят из разных источников: одно с клавиатуры, другое из файла.
Часто нужны оба: цикл перебирает значения, функция пересчитывает каждое. В одну строку это записывается так:
- for km in [100, 42, 7.5]: print(km_v_mili(km))
Цикл здесь отвечает только за «пройти по всем», функция — только за «пересчитать одно». Если завтра понадобится пересчёт из других мест программы, цикл придётся копировать вместе со списком, а функцию достаточно вызвать. Обратный вариант тоже бывает: функция, которая внутри себя перебирает список, например считает среднее по нему; но тогда её параметром служит сам список, и это уже тема статьи про списки и массивы.
Соперниками они не бывают, поэтому вопрос «что лучше» не имеет ответа. Выбирая, посмотрите, где стоят повторяющиеся куски: рядом, в одном списке, или в разных частях файла, куда данные добираются своими путями. В первом случае берут цикл, во втором функцию, а если картина смешанная, то и то, и другое сразу.
Позиция: функцию лучше заводить на третьем повторе
Школьные задачи нередко просят оформить решение функциями с первой строки. Моё мнение такое: заводить функцию на втором повторе рано. Два похожих куска ещё держатся в голове, а функция, написанная по двум примерам, обычно получает неудачные параметры: в третьем случае выясняется, что менялось и число, и коэффициент, и функцию переписывают. На третьем повторе картина ясна, и параметры называются без угадывания.
Исключение — задание, где функция требуется прямо в условии. Тогда пишите сразу, как просят.
Занятия в видеокомнате и экзамен
Репетитор не видит экран ученика, поэтому в чат стоит отправлять не одну функцию, а вызов и ожидаемый ответ: что вызывали, с каким аргументом и что должно было напечататься. Одна определённая функция без вызова ничего не показывает, и разбор начинается с вопроса «а что вы ей передавали».
На ЕГЭ по информатике в части заданий дана готовая функция, и нужно сказать, что она вернёт при заданном аргументе: умение читать функции работает там напрямую. Какие задания входят в первую часть, показано в карте заданий, а общий порядок экзамена описан в статье о его структуре.
Начать поиск:
- репетиторы по информатике, все направления
- репетиторы по информатике для подготовки к ЕГЭ
- репетиторы по информатике для 10–11 класса
- репетиторы по информатике, у которых есть видеозанятия
Вопросы и ответы
Чем параметр отличается от аргумента, и можно ли их путать? Параметр — имя в определении функции, аргумент — значение, которое вы передаёте при вызове. В разговоре их путают постоянно, и это терпимо. Различать нужно, когда читаете сообщение об ошибке или условие экзаменационного задания: там слова употребляются строго.
Сколько параметров допустимо у функции? Закона нет. Если их больше четырёх, функция нередко делает две вещи сразу, и её лучше разрезать.
Обязательно ли функции что-то возвращать? Нет. Функция без return просто выполняет действия, например печатает строку, и возвращает None. Но если результат нужен дальше в программе, return обязателен: print его не передаст.
Оставить заявку
- Татьяна Попова — Информатика и олимпиадное программирование · от 3 000 ₽
- Артём Игоревич Соловьёв — Информатика и математика: ОГЭ и ЕГЭ от практикующего разработчика · от 2 100 ₽
- Илья Германович Воронцов — Информатика: ЕГЭ, олимпиады и алгоритмы для студентов · от 1 700 ₽