Что такое функция в Python
Функция — это именованный блок кода, который выполняет одну задачу и запускается по имени. Сначала функцию объявляют словом def, а потом вызывают, написав имя и круглые скобки.
def hello():
print("Привет!")
print("Я — функция.")
hello()
hello()
Привет!
Я — функция.
Привет!
Я — функция.
Строки с def по последний отступ — это объявление: Python запоминает функцию, но ничего не выполняет. Код внутри запускается только при вызове hello(). Два вызова — два повтора. Если убрать скобки и написать просто hello, функция не выполнится: без скобок это лишь ссылка на неё.
Вы уже знаете много встроенных функций в Python: print() выводит текст, len() считает длину, int() превращает строку в число. Свои функции в Python устроены так же, просто их придумываете вы, и ограничений на их число нет. В Scratch похожую роль играют собственные блоки, которые создают кнопкой «Создать блок»: собрали скрипт, дали ему имя и вызываете где угодно. По федеральной образовательной программе вспомогательные алгоритмы изучают в 9 классе[1], а в Python они записываются именно как функции.
Как объявить функцию: def, имя и тело
Объявление функции состоит из 4 частей: слово def, имя, круглые скобки с параметрами и двоеточие, а под ним — тело с отступом в 4 пробела. Тело заканчивается там, где заканчивается отступ.
def draw_line(length):
print("-" * length)
draw_line(10)
print("Заголовок")
draw_line(10)
Имя функции подчиняется тем же правилам, что и имя переменной: латинские буквы, цифры и подчёркивание, не с цифры. Руководство PEP 8 рекомендует писать имена функций строчными буквами через подчёркивание — draw_line, count_vowels[2]. Хорошее имя функции — глагол, который говорит, что она делает: draw, calc_area, is_even. Функцию нужно объявить раньше, чем вызвать: Python читает файл сверху вниз, и вызов до def закончится ошибкой NameError.
Если тело функции пока не придумано, внутрь ставят pass — команду «ничего не делать». Пустое тело без неё вызовет ошибку отступа: после двоеточия в Python не может быть пустого блока. Не стоит бояться заготовок с pass — так программисты часто набрасывают план программы, а потом заполняют функции по одной.
Параметры и аргументы функции в Python
Параметры — это переменные в скобках при объявлении функции, а аргументы — значения, которые передают при вызове. При вызове draw_line(10) параметр length получает аргумент 10.
def introduce(name, age):
print("Меня зовут", name, "и мне", age, "лет")
introduce("Тимур", 11)
introduce("Лиза", 12)
introduce(age=10, name="Макс")
Аргументы раздаются параметрам по порядку: первый — первому, второй — второму. Если перепутать порядок, программа не упадёт, но скажет «Меня зовут 11». Чтобы не зависеть от порядка, аргументы можно передавать по имени: introduce(age=10, name="Макс"). Количество аргументов должно совпадать с числом параметров — иначе Python выдаст TypeError с текстом про missing или takes positional arguments. Разбор этой ошибки — на странице об ошибке TypeError.
Команда return: функция возвращает результат
Команда return завершает функцию и отдаёт значение туда, где её вызвали. Это главное отличие от print: print только показывает текст на экране, а return передаёт результат, с которым программа может работать дальше.
def square(x):
return x * x
a = square(4)
b = square(3) + square(2)
print(a, b)
print(square(square(2)))
16 13
16
| Что сравниваем | print внутри функции | return в функции |
| Куда идёт результат | На экран | В место вызова |
| Можно сохранить в переменную | Нет, будет None | Да |
| Можно использовать в выражении | Нет | Да: square(3) + 1 |
| Что после команды | Функция продолжает работу | Функция сразу заканчивается |
Если в функции нет return или он написан без значения, она возвращает специальное значение None. Это правило функции в Python соблюдают всегда, даже встроенные. Поэтому x = print("hi") кладёт в x именно None. Return может стоять в нескольких местах, например в разных ветках if: какой сработает первым, тот и завершит функцию. Функции, которые возвращают результат, легко проверять и соединять между собой, — так строят большие программы из маленьких деталей. Официальная документация Python описывает return в разделе об определении функций[3].
Значения параметров по умолчанию
Если у параметра есть значение по умолчанию, при вызове его можно не указывать: запись def greet(name, word="Привет") позволяет вызвать функцию и с 1, и с 2 аргументами.
def greet(name, word="Привет"):
return word + ", " + name + "!"
print(greet("Оля"))
print(greet("Оля", "Здравствуй"))
def power(base, exp=2):
return base ** exp
print(power(5), power(2, 10))
Параметры функции со значением по умолчанию пишут после обычных, и по-другому не получится: def greet(word="Привет", name) — синтаксическая ошибка. Встроенные функции тоже так устроены: у print есть параметры sep=" " и end="\n", поэтому мы их обычно не указываем. В качестве значения по умолчанию безопасно использовать числа, строки, True, False и None. Пустой список [] в этой роли — известная ловушка: он создаётся один раз и копит изменения между вызовами.
Область видимости: локальные и глобальные переменные
Переменная, созданная внутри функции, — локальная: она существует только во время вызова и снаружи не видна. Переменные, созданные вне функций, — глобальные: их можно читать внутри, но присваивание внутри создаст новую локальную.
bonus = 5
def add_bonus(score):
result = score + bonus
return result
print(add_bonus(10))
print(bonus)
Если после этого написать print(result) вне функции, будет NameError — так область видимости описана и в документации Python: переменная result жила только внутри вызова. Это удобно — у каждой функции свои «черновики», и одинаковые имена в разных функциях не мешают друг другу. Менять глобальные переменные изнутри можно через слово global, но в учебных программах лучше этого избегать: передайте значение параметром и верните результат через return. Ошибки с невидимыми переменными разобраны на странице об ошибке NameError.
Зачем нужны свои подпрограммы
Свои подпрограммы решают 3 задачи: убирают повторы кода, разбивают большую программу на понятные части и позволяют проверить каждую часть отдельно. Разбиение задачи на подзадачи — один из приёмов вычислительного мышления.
Представьте игру, где после каждого раунда нужно вывести счёт, проверить победу и нарисовать рамку. Без подпрограмм эти 15 строк повторятся в коде трижды, а исправлять ошибку придётся в трёх местах. С блоками show_score(), check_win() и draw_frame() основная программа читается как план: что происходит и в каком порядке. Jeannette Wing в статье о вычислительном мышлении описывает абстракцию и декомпозицию как приёмы, которыми решают большие сложные задачи[4]: вы думаете о том, что делает блок, а не о том, как она устроена внутри. Подробнее об этих приёмах — в статье про вычислительное мышление.
Задачи с автопроверкой
Чтобы закрепить тему, решите 6 задач в тренажёре вверху страницы: в каждой уже есть заготовка с заголовком, нужно написать тело. Нажмите «✓ Проверить» — программа запустит решение на тестах и покажет «Ожидалось» и «Получилось».
Задачи идут от одной строки с возвратом значения к решениям с условиями, циклом и значениями по умолчанию. Если застряли, нажмите «Подсказка»; «Показать решение» открывайте только после своих попыток. Решать с перерывами в несколько дней полезнее, чем всё за один вечер: эффект распределённой практики описан в обзоре Cepeda и соавторов[5]. Больше упражнений — площадь, НОД, простые числа — в подборке задач на функции.
Когда своя подпрограмма не нужна
Своя подпрограмма не нужна, если код выполняется один раз, занимает пару строк или в языке уже есть готовый инструмент с тем же действием. В этих 4 случаях лишняя обёртка только мешает читать программу.
- Действие встречается 1 раз и занимает 2 строки. Обёртка добавит ещё 2 строки и прыжок глазами по коду.
- Нужна сумма списка из 10 чисел. Встроенная
sum()уже делает это, писать свою незачем. - Функция в 50 строк делает 5 разных дел. Её лучше разделить на несколько маленьких, каждая — с одной задачей.
- Первая программа на 5 строк. Новичку сначала важно понять print, input и переменные, собственные блоки подождут.
«Функция обязательно должна что-то выводить на экран». Это миф: многие полезные подпрограммы ничего не печатают, а только отдают результат в место вызова.
«Переменная, созданная внутри def, видна во всей программе». Это не подтверждается: после завершения вызова локальная переменная исчезает, и обращение к ней снаружи вызывает NameError.
Чего делать нельзя
Нельзя вызывать подпрограмму раньше, чем она объявлена, — Python читает файл сверху вниз. Остальные правила касаются того, как она получает и отдаёт данные.
- Нельзя путать вывод на экран и возврат значения: если результат нужен дальше в программе, его надо вернуть, а не напечатать.
- Не следует забывать скобки при вызове:
helloбез()ничего не запустит. - Не стоит давать своему блоку имя встроенного —
sumилиlist: после этого стандартные версии перестанут работать. - Не допускается ставить параметр без значения после параметра со значением по умолчанию — будет SyntaxError.
- Не стоит использовать изменяемый список как значение по умолчанию: он сохраняет изменения между вызовами.
- Нельзя писать код после возврата значения в той же ветке и ждать, что он выполнится, — подпрограмма к этому моменту уже закончилась.
Источники
[1] Приказ Минпросвещения России от 18.05.2023 № 370 «Об утверждении федеральной образовательной программы основного общего образования».
[2] van Rossum G., Warsaw B., Coghlan N. PEP 8 — Style Guide for Python Code. Python Software Foundation, 2001.
[3] The Python Tutorial (официальная документация Python 3). Python Software Foundation.
[4] Wing J. M. Computational thinking // Communications of the ACM. 2006. Vol. 49, № 3. P. 33–35.
[5] Cepeda N. J., Pashler H., Vul E., Wixted J. T., Rohrer D. Distributed practice in verbal recall tasks: A review and quantitative synthesis // Psychological Bulletin. 2006. Vol. 132, № 3. P. 354–380.
Вопросы и ответы
Сколько параметров можно объявить?
Сколько угодно, в том числе ни одного. Но если их больше 4–5, код становится трудно читать — возможно, стоит разделить задачу на части.
Можно ли вернуть сразу два значения?
Да: запись через запятую после возврата отдаёт пару, а при вызове её можно разложить по двум переменным: x, y = f().
Чем метод отличается от обычной подпрограммы?
Метод вызывается через точку у конкретного объекта, например "кот".upper(). Обычную подпрограмму вызывают просто по имени, как len("кот").
Можно ли вызывать одну подпрограмму из другой?
Конечно, так и строят программы: один блок использует результаты других. Он может вызывать даже сам себя — это называется рекурсией, но новичкам с ней лучше подождать.
Где писать объявления в файле?
Принято собирать все объявления в начале файла, после строк с import, а основной код — ниже. Так программу легче читать.
Что значит None в выводе?
Так Python показывает «ничего». Чаще всего None появляется, когда печатают результат подпрограммы, в которой забыли вернуть значение.