Возвращаемые значения функций в языке Python
Основы возврата значений из функций
Функция в Python может не только выполнять действия, но и возвращать результат с помощью ключевого слова return. Без return функция неявно возвращает None. Понимание механизма возврата необходимо для построения чистых, повторно используемых блоков кода.
Самый распространённый способ - указать одно значение после return. Функция завершается и передаёт это значение вызывающему коду.
def square(x):
return x * x
result = square(5)
print(result) # 25аргументы print python (аргументы функции print в python)
Здесь square возвращает квадрат числа. Вызов функции подставляется вместо возвращаемого значения.
Типичная ошибка: забыть return - функция вернёт None.
def square_bad(x):
x * x # нет return
print(square_bad(5)) # NonePython 3 аргументы (аргументы в python 3)
Решение - всегда явно указывать return, даже если нужно вернуть None.
Как вернуть несколько значений из функции?
В Python можно вернуть несколько значений, упаковав их в кортеж (tuple), список или словарь. Самый идиоматичный способ - кортеж без скобок.
def stats(numbers):
mn = sum(numbers) / len(numbers)
mx = max(numbers)
return mn, mx # кортеж
t = stats([1, 2, 3, 4])
print(t) # (2.5, 4)
mean, top = t # распаковка
print(mean, top) # 2.5 4
аргумент параметр python (аргументы и параметры в python)
Проблема: если забыть распаковать результат, получится кортеж. Если функция возвращает много значений, сложность чтения возрастает.
Решение: использовать именованные кортежи (namedtuple) или классы данных.
Как вернуть значение, зависящее от условия?
Допускается несколько операторов return в разных ветках. Функция завершается на первом встреченном return.
def sign(x):
if x > 0:
return 1
elif x < 0:
return -1
return 0
print(sign(10)) # 1
print(sign(-5)) # -1
print(sign(0)) # 0аргумент класса python (аргументы класса python)
Ошибка: после return код не выполняется. Если забыть return в одной из веток, функция вернёт None.
Рекомендуется проверять все пути исполнения.
Как вернуть «ничего» (пустой результат)?
Явный return None или просто return. Часто используется для обозначения неудачи.
def find_even(lst):
for item in lst:
if item % 2 == 0:
return item
return None # не найдено
print(find_even([1, 3, 5])) # NonePython аргументы строки (аргументы строки в python (командная строка))
Как вернуть результат с сохранением состояния? (генераторы)
Ключевое слово yield превращает функцию в генератор, который возвращает последовательность значений по одному.
def countdown(n):
while n > 0:
yield n
n -= 1
for val in countdown(3):
print(val) # 3, 2, 1аргумент метода python (аргументы метода python)
Путаница: yield не является разновидностью return. Если в функции есть и return, и yield, то return завершает генерацию (но значение return не попадает в последовательность).
Для простых возвратов одной коллекции используйте обычный return.
Как вернуть результат с аннотацией типа?
Аннотации помогают IDE и документации.
from typing import Optional
def safe_div(a: float, b: float) -> Optional[float]:
if b == 0:
return None
return a / bРасширенные примеры работы с возвратом результатов
Возврат нескольких значений с распаковкой в переменные
Кортеж - самый популярный способ. Но если значений много, лучше использовать именованные кортежи.
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y', 'z'])
def create_point():
return Point(1.0, -2.0, 3.5)
p = create_point()
print(p.x, p.y, p.z) # 1.0 -2.0 3.51.0 -2.0 3.5
Возврат словаря для гибкости
Когда порядок не важен или ключи описывают смысл.
def user_info(user_id):
# имитация запроса к БД
return {
'id': user_id,
'name': 'Алексей',
'roles': ['admin', 'user']
}
info = user_info(42)
print(info['name']) # АлексейАлексей
Функция с несколькими return внутри цикла
Поиск первого вхождения.
def first_negative(nums):
for i, n in enumerate(nums):
if n < 0:
return i, n
# если не найдено
return None, None
ind, val = first_negative([5, -3, 8])
print(ind, val) # 1 -31 -3
Рекурсивная функция с возвратом
Факториал как классика.
def factorial(n):
if n < 2:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120120
Генератор как альтернатива возврату списка
Экономия памяти при работе с большими наборами данных.
def squares_up_to(n):
for i in range(1, n+1):
yield i*i
gen = squares_up_to(10)
print(list(gen)) # [1,4,9,16,25,36,49,64,81,100][1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Возврат результата с мемоизацией
Сохраняем результат для повторного вызова с теми же аргументами.
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(50)) # 1258626902512586269025
Возврат лямбда-функции
Функция высшего порядка возвращает другую функцию.
def multiplier(factor):
return lambda x: x * factor
double = multiplier(2)
print(double(7)) # 1414
Проблема с изменяемыми объектами по умолчанию
Если вернуть список, созданный как значение по умолчанию, изменения сохраняются.
def bad_append(item, lst=[]):
lst.append(item)
return lst
print(bad_append(1)) # [1]
print(bad_append(2)) # [1, 2] - неожиданно![1] [1, 2]
Исправление - использовать None и создавать новый список внутри.
def good_append(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lstВозврат NotImplemented для операторов
Специальное значение для поддержки двойной диспетчеризации.
class Vector:
def __mul__(self, other):
if isinstance(other, Vector):
return self.x * other.x + self.y * other.y
return NotImplemented