Функции в Python: def, параметры и return на примерах

Python Автор: Среда и версия: CPython 3.14.7
содержание

Функция в Python — именованный фрагмент кода, который вызывают с нужными данными. Инструкция def определяет функцию, параметры принимают входные значения, а return передаёт результат вызывающему коду. Для расчёта длительности удобно вернуть число секунд: его потом можно сложить с другим интервалом или вывести на экран.

Блоки с кнопкой запуска самостоятельны: определение функции повторяется там, где оно нужно.

Как определить и вызвать функцию через def

Пусть занятие длится 2 минуты 15 секунд. Функция переведёт этот интервал в секунды:

def duration_seconds(minutes, seconds):
    total = minutes * 60 + seconds
    return total

lesson = duration_seconds(2, 15)
print(lesson)
print(lesson + 30)
135
165

duration_seconds — имя функции. После имени стоят параметры в скобках и двоеточие. Две строки с отступом образуют тело: сначала вычисляется total, затем результат возвращается наружу. Строка lesson = ... уже без отступа и выполняется после определения.

Само определение не выполняет расчёт. Его запускает выражение duration_seconds(2, 15). Если написать только имя duration_seconds без скобок, получится объект функции, а не число секунд. Синтаксис определения описан в учебнике Python.

Python / 01

return передаёт 135, print выводит 135

Расчёт длительности и вывод результатаПервый шаг: аргументы 2 и 15 становятся параметрами minutes и seconds. Второй шаг: функция вычисляет 2 умножить на 60 плюс 15 и возвращает 135. Третий шаг: переменная lesson хранит 135, а отдельный вызов print выводит это число в консоль.01 / аргументы02 / тело функции03 / результатminutes = 2seconds = 152 * 60 + 15return 135lesson = 135число для расчётовprint(lesson)135текст в консоли
Расчёт возвращает число в lesson. Консоль получает его только после отдельного вызова print(lesson).

Параметры и аргументы: в чём разница

Параметры — имена в определении: minutes и seconds. Аргументы — значения конкретного вызова: 2 и 15. При позиционной передаче значения сопоставляются слева направо; при именованной имя указано явно.

def duration_seconds(minutes, seconds):
    return minutes * 60 + seconds

print(duration_seconds(2, 15))
print(duration_seconds(minutes=2, seconds=15))
print(duration_seconds(seconds=15, minutes=2))
print(duration_seconds(15, 2))
135
135
135
902

Последний вызов синтаксически верен, но означает 15 минут 2 секунды. Имена аргументов помогают избежать такой перестановки. Допустим и смешанный вызов duration_seconds(2, seconds=15).

Один параметр нельзя передать дважды. duration_seconds(2, minutes=3, seconds=15) вызовет TypeError: значение minutes уже пришло первым позиционным аргументом. Если обязательный аргумент пропущен, как в duration_seconds(2), Python тоже сообщит TypeError. Когда число входных значений заранее неизвестно, нужны отдельные приёмы с args и kwargs.

Чем return отличается от print

return завершает текущий вызов и задаёт его значение. print пишет текст в поток вывода; собственный результат printNone. Поэтому функция, которая только печатает число, неудобна для последующих расчётов.

def show_duration(minutes, seconds):
    print(minutes * 60 + seconds)

def duration_seconds(minutes, seconds):
    return minutes * 60 + seconds

printed = show_duration(2, 15)
returned = duration_seconds(2, 15)

print("printed:", printed)
print("returned:", returned)
assert printed is None
assert returned == 135
135
printed: None
returned: 135

Первая строка вывода появилась внутри show_duration. Она не стала значением переменной printed. Попытка посчитать printed + 30 закончится ошибкой типов.

Без return обычная функция возвращает None. То же происходит при пустом return и при достижении конца тела. Точные правила приведены в справочнике по return. Если функция должна считать длительность, возвращай число; печатай его уже там, где результат показывают пользователю.

Почему None появляется только на некоторых входах

Причина может быть в ветке, для которой забыли результат:

def broken_duration(minutes, seconds):
    if minutes > 0:
        return minutes * 60 + seconds

print(broken_duration(2, 15))
print(broken_duration(0, 15))
135
None

Интервал 0 минут 15 секунд допустим, но условие для него ложно. Исправление здесь — убрать ненужную проверку minutes > 0 и возвращать выражение для обоих случаев. Отрицательные значения лучше отклонять явно; ниже есть законченный вариант с проверкой входа.

Значения по умолчанию

Если остаток секунд часто равен нулю, запиши seconds=0 в определении:

def duration_seconds(minutes, seconds=0):
    return minutes * 60 + seconds

print(duration_seconds(2))
print(duration_seconds(2, 15))
print(duration_seconds(minutes=0, seconds=45))
120
135
45

Значение по умолчанию используется только при отсутствии аргумента. Явный None не означает «возьми ноль»: при duration_seconds(2, None) выражение попыталось бы сложить число с None.

В def remember(value, history=[]) список создаётся при выполнении определения и переиспользуется в следующих вызовах без history. Если каждому вызову нужен новый список, создавай его внутри:

def remember(value, history=None):
    if history is None:
        history = []
    history.append(value)
    return history

print(remember(135))
print(remember(60))

shared = []
remember(135, shared)
remember(60, shared)
print(shared)
[135]
[60]
[135, 60]

Первые два вызова независимы. Последние два изменяют один список, потому что мы сами передали shared. Это различие разобрано в Python FAQ; свойства таких объектов — в статье об изменяемости.

Где живут локальные переменные

Внутреннее имя total не становится внешней переменной. Даже если снаружи есть переменная с тем же именем, обычное присваивание в функции создаёт локальную привязку:

total = 999

def duration_seconds(minutes, seconds):
    total = minutes * 60 + seconds
    return total

result = duration_seconds(2, 15)
print(result)
print(total)
135
999

Каждый вызов получает собственные локальные имена. Результат доступен снаружи через return, поэтому здесь нет причины добавлять global. Правила поиска имён и областей видимости закреплены в модели выполнения Python.

Локальность имени не делает копию переданного объекта. В предыдущем примере history.append(...) изменял общий список shared: два имени ссылались на один объект.

Законченная функция с проверкой входа

Зафиксируем договор: minutes — целое неотрицательное число, seconds — целый остаток от 0 до 59. Строки из формы и значения True/False этот вариант не принимает. Преобразование пользовательского ввода лучше выполнять до вызова, отдельно обрабатывая ошибки преобразования типов.

def duration_seconds(minutes, seconds=0):
    """Вернуть длительность в секундах из минут и остатка секунд."""
    if type(minutes) is not int or type(seconds) is not int:
        raise TypeError("minutes и seconds должны быть целыми числами")
    if minutes < 0 or not 0 <= seconds < 60:
        raise ValueError("нужны minutes >= 0 и 0 <= seconds < 60")
    return minutes * 60 + seconds

assert duration_seconds(0) == 0
assert duration_seconds(2, 15) == 135
assert duration_seconds(1) == 60
assert duration_seconds(seconds=59, minutes=0) == 59

for arguments, expected_error in [
    ((-1, 0), ValueError),
    ((0, 60), ValueError),
    (("2", 15), TypeError),
    ((True, 0), TypeError),
]:
    try:
        duration_seconds(*arguments)
    except expected_error:
        continue
    raise AssertionError(f"ожидалась ошибка для {arguments!r}")

print("Проверены обычные, граничные и ошибочные входы")
Проверены обычные, граничные и ошибочные входы

Здесь type(value) is int выбран намеренно: условие принимает именно встроенный int, исключая bool и подклассы. При недопустимых аргументах функция выбрасывает исключение через raise; assert в примере проверяет её поведение.

Если задача допускает 90 секунд как отдельный аргумент, ограничение < 60 нужно изменить: оно описывает выбранный формат входа, а не правило языка. Для получения строки вроде 02:15 переходи к форматированию длительности. Чтобы закрепить def и return, измени функцию так, чтобы она принимала ещё и часы, и добавь проверку: 1 час 2 минуты 3 секунды дают 3 723 секунды.

Источники