Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 3 из 20 Начальный 15 мин 100 XP

Return в Python: функция возвращает результат

print показывает значение человеку, return отдаёт программе. Учимся возвращать результат, класть его в переменную и использовать в выражениях — и не путать return с print.

Редакция Питоники

Функции из первых двух уроков печатают: print_line рисует линию, greet здоровается. Печать видит человек, но программа из неё ничего не достанет: нельзя сложить два напечатанных числа, положить напечатанный список в переменную, передать дальше. Для отдачи значения программе у функции есть return — оператор возврата. Это граница между функциями-инструкциями для глаз и функциями-вычислителями для программы.

Функция, которая только печатает

Посмотрим, что на самом деле отдаёт функция с print, если её результат попробовать сохранить:

печать внутри — None снаружи
def show_total(prices):
    print(sum(prices))

show_total([100, 200, 50])
result = show_total([100, 200, 50])
print(result)
Вывод
350
350
None

Первая строка вывода — работа print внутри функции. Вторая — тот же print при втором вызове, результат которого мы положили в переменную result. Третья — и вот что лежит в result: None. Функция напечатала сумму, но вернула ничего: без return функция отдаёт None — специальное значение «ничего».

ошибка: арифметика с None
# Так не запускается: функция вернула None, а None умножать нельзя
def show_total(prices):
    print(sum(prices))

result = show_total([10, 20])
result = result * 2
Python ответит TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'. Печать прошла, но вернулась None — с ней нельзя считать. Ошибка вылезает не в функции, а там, где её результат попробовали использовать.

return: функция отдаёт значение

Заменим print на return — и результат станет программным:

та же функция, но с return
def total(prices):
    return sum(prices)

result = total([100, 200, 50])
print(result)
print(result * 2)
Вывод
350
700

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

print внутри функцииreturn
Кому адресованоЧеловеку на экранеПрограмме
Что можно с результатомТолько посмотретьПрисвоить, посчитать, передать дальше
Что вернёт вызовNoneУказанное значение
Типичная рольОтчёты и сообщенияВычисления и обработка данных

Вернувшееся значение участвует в выражениях прямо на месте вызова — переменная даже не обязательна:

результат — прямо в выражении
def rub_to_eur(rubles, rate):
      return rubles / rate

print(rub_to_eur(1000, 100))
budget = rub_to_eur(5000, 100)
print('Бюджет:', budget, 'евро')
Вывод
10.0
Бюджет: 50.0 евро

return завершает функцию

return не только отдаёт значение, но и немедленно заканчивает функцию. Первый сработавший return — последний шаг вызова:

два return, сработает один
def check_age(age):
    if age < 18:
        return 'вход запрещён'
    return 'добро пожаловать'

print(check_age(15))
print(check_age(21))
Вывод
вход запрещён
добро пожаловать

Для age = 15 сработал первый return — функция закончилась, до второй строки return тело не дошло. Для 21 условие ложно, и отработал нижний return. Веток может быть сколько угодно, но за один вызов выполнится ровно одна.

код после return недостижим
def double(n):
    return n * 2
    print('эта строка не выполнится')

print(double(5))
Вывод
10

print внутри double стоит после return и не выполняется никогда: return уже завершил функцию. Python не ругается на такой код — он просто честно его не запускает. Увидели строки после return в функции без условий — это мёртвый код, его стоит удалить.

return без значения: досрочный выход

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

пустой return как стоп-сигнал
def log_out(msg):
    if msg == 'стоп':
        return
    print('лог:', msg)

log_out('работаю')
log_out('стоп')
log_out('заканчиваю')
Вывод
лог: работаю
лог: заканчиваю

Сообщение «стоп» прервало функцию до печати: второй вызов не оставил следа в логе. Без if такой стоп не сделать — return посреди тела завершил бы функцию всегда, и лог печатал бы только первую строку.

Собираем: функция-вычислитель в работе

Финальный пример: функция считает средний балл, а вызывающий код решает, что с ним делать. Считает функция, печатает и решает — программа:

функция возвращает, программа решает
def average(numbers):
    return sum(numbers) / len(numbers)

scores = [4, 5, 3, 5]
avg = average(scores)
print('Средний балл:', avg)
if avg >= 4:
    print('Зачёт')
else:
    print('Пересдача')
Вывод
Средний балл: 4.25
Зачёт

average ничего не печатает — она только возвращает число. Печать и решение о зачёте живут в вызывающем коде: такую функцию можно переиспользовать где угодно, не трогая её тело. Считать и возвращать умеет теперь и ваша функция; данные в неё попадают аргументами из урока про аргументы, а необязательные параметры с запасными значениями — следующий шаг, урок про умолчания.

Два значения из одной функции

Вопросов у данных часто два: какой товар самый дешёвый и сколько он стоит. Возвращать список из двух элементов неудобно — на вызывающей стороне непонятно, что где. Python решает это кортежем: напишите return name, price — и получите кортеж, который распаковывается в две переменные одной строкой.

кортеж на выходе
def cheapest(cart):
    best = cart[0]
    for item in cart:
        if item[1] < best[1]:
            best = item
    return best[0], best[1]

name, price = cheapest([('Хлеб', 240), ('Сыр', 45), ('Молоко', 80)])
print(name, price)
Вывод
Сыр 45

Строка name, price = cheapest(...) — это распаковка: Python знает, что справа кортеж из двух элементов, и раскладывает их по переменным. Если элементов в кортеже больше, чем переменных слева, будет ValueError: too many values to unpack. Обратная история тоже работает: верните кортеж целиком одной переменной — и он придёт как один объект, который можно положить в список или сравнить с другим кортежем.

Ветка, которая забыла return

Самая неприятная ошибка в функциях с возвратом — не SyntaxError, а тихий None. Функция с условием, где в одной ветке есть return, а в другой забыли, выглядит вполне рабочей: читается, запускается, ошибок не даёт. Она просто в одной из веток отдаёт None вместо значения.

забытый return в одной ветке
def discount(price, has_card):
    if has_card:
        return price - price // 10
    return price


def discount_bad(price, has_card):
    if has_card:
        return price - price // 10


print(discount(500, True))
print(discount_bad(500, False))
Вывод
450
None

Первый вызов вернул 450 — скидка посчитана. Второй вернул None: ветка без карты просто дошла до конца тела. Дальше по программе кто-то сложит это значение с суммой заказа — и получит TypeError про NoneType, и ошибка укажет совсем не туда, где дело вышло из-под контроля. Правило простое: если функция в одной ветке возвращает значение, в другой ветке тоже должен быть return.

Возвращать или печатать

Границу между print и return проще всего держать в голове одной таблицей. Она отвечает на вопрос «кто будет пользоваться результатом», и почти всегда ответ очевиден.

СитуацияЧто делатьПочему так
Функция считает или выбираетreturn значениерезультат пойдёт дальше по программе
Функция показывает отчёт человекуprintсмотреть будут люди, а не программа
Нужно и посчитать, и показатьreturn, печать — в вызывающем кодеиначе результат не достанешь
Хочется и то и другое в одной функциидве функции: вычислитель и принтеродна функция — одна задача

Мы держимся правила: вычислитель возвращает, принтер печатает. Когда в задании просят «посчитать и сразу показать», мы не ломаем правило, а заводим пару функций: одна считает, вторая печатает результат. Две маленькие функции читаются лучше одной с двойным назначением, и их легко заменить в тестах.

None — это тоже результат

Отдельная тема — как выглядит «ничего» в возвращаемом значении. Если поиск не нашёл подходящего элемента, возвращать 0 или пустую строку неправильно: ноль — это полноценное число, пустая строка — полноценный текст. Правильный ответ — None, и вызывающий код должен его учитывать.

None как признак «не нашлось»
def find_user(users, name):
    for user in users:
        if user['name'] == name:
            return user
    return None


users = [{'name': 'Аня', 'age': 24}, {'name': 'Боря', 'age': 31}]
found = find_user(users, 'Аня')
missing = find_user(users, 'Коля')

if missing is None:
    print('Коля не найден')
else:
    print(missing)
Вывод
Коля не найден

Проверка is None, а не == None: так пишут, когда хотят точно убедиться, что значения нет. Возвращать None из функции поиска — сознательное решение, и вызывающий код обязан его ждать. Дальше эта договорённость превращается в проверки и исключения — урок про ошибки функций разбирает, как Python сообщает о том, что пошло не так.

Практика: заказ, который считает функция

Соберём вместе всё, что разобрали: функция считает и возвращает, вызывающий код печатает и принимает решение. Порядок именно такой — иначе решение пришлось бы зашивать в тело функции.

итог по заказу
def order_total(items):
    total = 0
    for name, price in items:
        total = total + price
    return total

order = [('Хлеб', 45), ('Молоко', 80)]
total = order_total(order)
print('Заказ на', total, 'руб.')
if total > 100:
    print('Доставка бесплатно')
Вывод
Заказ на 125 руб.
Доставка бесплатно

Функция order_total ничего не знает про доставку и про порог в 100 рублей — она просто считает. Всё остальное живёт в вызывающем коде, поэтому порог легко поменять, а саму функцию — вызвать из другого отчёта. Считать и возвращать вы теперь умеете; данные в функцию попадают аргументами из урока про аргументы, а необязательные параметры с запасными значениями — это урок про умолчания.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

def f(x):
    return x * 3

y = f(4)
print(y + 1)
def f():
    print('внутри')

x = f()
print(x)
def f(x):
    if x > 5:
        return 'большой'
    return 'маленький'

print(f(3))
print(f(10))
Проверь себя
0 / 9

1. Что делает return?

2. Что вернёт функция без return?

3. Функция объявлена как def f(x): return x * 3. Что окажется в y после y = f(4)?

4. Что выполнится из строк, стоящих в теле функции после сработавшего return?

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

6. Сколько return выполнится за один вызов функции?

7. В функции написан только if: return 1, а после if никакого return нет. Что вернёт вызов, когда условие ложно?

8. Функция вернула кортеж из двух чисел. Как его получить в двух переменных?

9. Что вернёт функция, в которой есть и print, и return?

Карточки терминов
Запомнено: 0 / 8
Практика

Напиши функцию discount(price), которая возвращает цену со скидкой десятой части: price - price // 10. Примени её к списку цен [500, 200, 1000], собери итоговую сумму через аккумулятор и напечатай строку «Итого со скидкой: ...».

practice.py
Вопросы и ответы по уроку

Чем return отличается от print в функции?

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

Урок 2: аргументы функции

Что вернёт функция без return?

None — специальное значение «ничего». Поэтому result = функция_с_print даёт None, а арифметика с таким результатом падает с TypeError про NoneType. Если нужен результат — пишите return значение.

Может ли в функции быть несколько return?

Да, в разных ветках условий: за один вызов сработает ровно один — первый, до которого дошло выполнение. Он же завершит функцию, поэтому код после сработавшего return не выполняется.

Как вернуть из функции два значения?

Написать их через запятую: return best, worst — Python упакует их в кортеж, и вызывающий код распакует в две переменные: b, w = функция(). Это удобная связка, когда функция отвечает сразу на два вопроса о данных.

Почему функция возвращает None, хотя я ожидал число?

Скорее всего, в одной из веток забыт return: если условие ложно, тело просто доходит до конца и функция возвращает None. Ошибка не выглядит как ошибка — она всплывёт позже, там, где с результатом попробуют посчитать. Проверьте, что в каждой ветке есть return.

Можно ли в одной функции и напечатать, и вернуть значение?

Технически да, но мы так не делаем: print адресован человеку, return — программе. Смешивание делает функцию неоднозначной — непонятно, за что её звать. Лучше две функции: одна считает и возвращает, вторая печатает результат.

Что вернёт функция, если выполнение дошло до конца тела, а return не встретился?

None. Python не выдаёт ошибку и не предупреждает — функция просто отдаёт «ничего». Именно поэтому мы пишем return в конце тела как запасной вариант или в каждой ветке: тогда результат предсказуем в любом случае.

Понравился урок? Сошлитесь на него

«print показывает значение человеку, а return отдаёт значение программе.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.