SkillPy

Функции в Python: от def до lambda

Время чтения20 мин чтения
Опубликовано12 августа 2026 г.
Средне
Python
Синтаксис
Начинающим
Функции
Функции в Python: от def до lambda
Кот-наставник

— Привет! Я кот-наставник, провожу людей через Python на платформе SkillPy. И вот что скажу: функции — это момент, когда код перестаёт быть списком инструкций и становится программой.

— Ты уже вызывал функции: print(), input(), len(). Но писать свои — совсем другое дело. Здесь начинается осознанное программирование.

— Не пугайся: концепция простая, а возможностей сразу много. Разберём всё по порядку — от первого def до lambda.

Функции в Python — это именованные блоки кода, которые можно вызывать сколько угодно раз. Без них программа растёт в одну длинную простыню: сто строк, двести, пятьсот — и всё в одном потоке. С функциями программа разбивается на маленькие детали, каждая из которых делает одну вещь и делает её хорошо. В этом гайде разберём функции в Python с нуля: объявление через def, параметры и аргументы, возврат значений через return, область видимости, аргументы по умолчанию, *args и **kwargs, а также lambda-функции и их границы. Все примеры запускаются в Python 3.12 без библиотек. Если пока плавают int, str и bool, загляни в гайд Типы данных в Python: полный гайд для начинающих.

Функции в Python: коротко

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

def greet(name):  # объявление функции через def
    return f"Привет, {name}!"  # return отдаёт результат

message = greet("Аня")  # вызов по имени со скобками
print(message)
Привет, Аня!

Зачем нужны функции в Python?

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

# Заказ 1
price1 = 300
discount1 = 10
total1 = price1 - price1 * discount1 / 100
print(f"Итого: {total1} руб.")

# Заказ 2 — та же логика, другой заказ
price2 = 450
discount2 = 15
total2 = price2 - price2 * discount2 / 100
print(f"Итого: {total2} руб.")

# Заказ 3 — снова копируем...
price3 = 520
discount3 = 5
total3 = price3 - price3 * discount3 / 100
print(f"Итого: {total3} руб.")
Итого: 270.0 руб.
Итого: 382.5 руб.
Итого: 494.0 руб.

Работает, но проблем три:

  • ❌ Код дублируется. Формула одна — написана трижды. Если нужно изменить логику скидки, править придётся в трёх местах.
  • ❌ Легко ошибиться. Скопировал, забыл поменять переменную — и один заказ считается по чужой скидке.
  • ❌ Не масштабируется. Заказов будет сто — что, сто раз копировать?

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

Тот же расчёт, но через функцию:

def calculate_price(price, discount):
    total = price - price * discount / 100
    return total

print(f"Итого: {calculate_price(300, 10)} руб.")
print(f"Итого: {calculate_price(450, 15)} руб.")
print(f"Итого: {calculate_price(520, 5)} руб.")
Итого: 270.0 руб.
Итого: 382.5 руб.
Итого: 494.0 руб.

Тот же результат, но формула живёт в одном месте. Нужно поменять логику — правишь функцию, и все вызовы автоматически используют новую версию. Это и есть принцип DRY: Don't Repeat Yourself — не повторяй себя.

Объявление функции: def и вызов

Функция — это именованный блок кода, который выполняет определённую задачу. Функция может принимать данные (параметры), обрабатывать их и возвращать результат.

Объявление функции в Python начинается с ключевого слова def. После него — имя функции, скобки с параметрами (если они есть) и двоеточие. Тело функции — все строки с отступом внутри.

Простая функция без параметров:

def greet():
    print("Привет из функции!")

greet()
greet()
Привет из функции!
Привет из функции!

Что произошло: 1. def greet() — объявили функцию с именем greet и без параметров. 2. Тело функции — одна строка print("Привет из функции!"). 3. greet() — вызвали функцию. Python выполнил тело и вернулся к следующей строке. 4. Вызвали ещё раз — функция выполнилась заново.

Параметры и аргументы функции

Параметры — это переменные в объявлении функции. Аргументы — это значения, которые передаются при вызове. Параметры — это «ячейки» в определении, аргументы — то, что в них кладут.

Функция с одним параметром:

def greet_user(name):
    print(f"Привет, {name}!")

greet_user("Анна")
greet_user("Игорь")
Привет, Анна!
Привет, Игорь!

Здесь name — параметр, а "Анна" и "Игорь" — аргументы. Функция использует name внутри тела, и при каждом вызове name получает новое значение.

Функция с несколькими параметрами:

def print_receipt(item, price, quantity):
    total = price * quantity
    print(f"{item} × {quantity} = {total} руб.")

print_receipt("Кофе", 150, 2)
print_receipt("Круассан", 90, 3)
Кофе × 2 = 300 руб.
Круассан × 3 = 270 руб.

Параметры передаются по позиции: первый аргумент идёт в первый параметр, второй — во второй. Поэтому порядок важен. Если перепутать price и quantity, результат будет другим.

Возвращаемое значение: return

Функция может не только выводить результат на экран, но и возвращать его в программу. Для этого используется ключевое слово return. Возвращённое значение можно сохранить в переменную или использовать дальше.

def add(a, b):
    return a + b

result = add(5, 3)
print(result)
print(add(10, 20))
8
30

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

Использование return для раннего выхода:

def check_age(age):
    if age < 18:
        return "Доступ запрещён"
    return "Доступ разрешён"

print(check_age(15))
print(check_age(25))
Доступ запрещён
Доступ разрешён

Если age < 18, функция доходит до return "Доступ запрещён" и выходит. Второй return не выполняется. Если условие ложно — выполняется второй return. Сам оператор ветвления разбираем в гайде if, elif и else в Python: условия с примерами.

Функция без return возвращает None

Если в функции нет return или return написан без значения, функция возвращает None — специальное значение, означающее «ничего».

def say_hello(name):
    print(f"Привет, {name}!")

result = say_hello("Мир")
print(result)
print(type(result))
Привет, Мир!
None
<class 'NoneType'>

Функция say_hello выводит текст на экран, но не возвращает результат. Поэтому result содержит None. Это частая путаница: print() внутри функции — это вывод на экран, а не возврат значения. Если нужно получить результат из функции, используй return.

Кот-наставник

— Запомни простое правило: print — это показать, return — это отдать. Если функция считает что-то полезное, она должна return, а не print. Вывод на экран — побочный эффект, а не результат.

Область видимости: локальные и глобальные переменные

Переменные, созданные внутри функции, живут только внутри неё. Снаружи их не видно. Это называется локальной областью видимости.

def calculate():
    result = 42

calculate()
print(result)
NameError: name 'result' is not defined

Переменная result создана внутри calculate(). Когда функция завершилась, result исчезла. Снаружи её не существует — отсюда NameError. Если Python не находит имя, проверь все причины по чек-листу из статьи NameError: name is not defined в Python — как исправить.

Переменные снаружи функции видны внутри, но изменять их напрямую нельзя:

counter = 0

def increment():
    counter = counter + 1

increment()
UnboundLocalError: cannot access local variable 'counter' where it is not associated with a value

Python видит присваивание counter = внутри функции и решает, что counter — локальная переменная. Но при этом пытается использовать её значение до того, как присвоила. Отсюда ошибка. Подробный разбор механики области видимости и безопасного исправления через параметр и return — в статье UnboundLocalError в Python: причина и как исправить.

Правильный подход — не менять глобальные переменные из функции, а принимать данные через параметры и возвращать результат через return:

counter = 0

def increment(value):
    return value + 1

counter = increment(counter)
print(counter)

counter = increment(counter)
print(counter)
1
2

Аргументы по умолчанию

Параметру можно задать значение по умолчанию. Если при вызове аргумент не передан, используется оно.

def greet(name, greeting="Привет"):
    print(f"{greeting}, {name}!")

greet("Анна")
greet("Игорь", "Здравствуй")
Привет, Анна!
Здравствуй, Игорь!

Первый вызов не передаёт greeting — используется значение по умолчанию "Привет". Второй вызов передаёт "Здравствуй" — оно заменяет значение по умолчанию.

Именованные аргументы

При вызове функции аргументы можно передавать по имени, а не только по позиции. Это делает код читаемее, особенно когда параметров много.

def create_user(name, role, active=True):
    print(f"Пользователь: {name}, роль: {role}, активен: {active}")

create_user("Анна", "admin")
create_user("Игорь", "editor", active=False)
create_user(role="moderator", name="Олег")
Пользователь: Анна, роль: admin, активен: True
Пользователь: Игорь, роль: editor, активен: False
Пользователь: Олег, роль: moderator, активен: True

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

*args и **kwargs: переменное число аргументов

Иногда заранее неизвестно, сколько аргументов передадут функции. Для этого в Python есть *args — сбор всех позиционных аргументов в кортеж, и **kwargs — сбор всех именованных аргументов в словарь.

*args — любое количество позиционных аргументов:

def sum_all(*numbers):
    total = 0
    for n in numbers:
        total += n
    return total

print(sum_all(1, 2, 3))
print(sum_all(10, 20, 30, 40, 50))
print(sum_all())
6
150
0

Внутри функции numbers — это кортеж со всеми переданными аргументами: его удобно перебрать циклом for, как разобрано в гайде Циклы в Python: for, while, break и continue. Можно передать ноль, один, сто — функция отработает одинаково.

**kwargs — именованные аргументы в словарь:

def print_info(**info):
    for key, value in info.items():
        print(f"{key}: {value}")

print_info(name="Анна", age=25, city="Москва")
name: Анна
age: 25
city: Москва

Внутри функции info — это словарь. Ключи — имена аргументов, значения — то, что передали. kwargs расшифровывается как keyword arguments. Если сама структура dict пока непривычна, её создание, методы и перебор разобраны в гайде Словари в Python: создание, методы и перебор.

*args и kwargs — в чём разница?

Критерий*args**kwargs
ЗвёздочкиОдна *Две **
Что собираетПозиционные аргументыИменованные аргументы
Тип внутри функцииКортеж (tuple)Словарь (dict)
Пример вызоваf(1, 2, 3)f(name="Анна", age=25)

Lambda-функции: анонимные функции в Python

lambda — это способ создать функцию в одну строку без def. Такая функция не имеет имени (поэтому «анонимная») и ограничена одним выражением.

Lambda-функция — это анонимная функция, записанная в одно выражение. Синтаксис: lambda параметры: выражение. Результат выражения — это возвращаемое значение.

Сравнение обычной функции и lambda:

# Обычная функция
def square(x):
    return x ** 2

# То же самое через lambda
square_lambda = lambda x: x ** 2

print(square(5))
print(square_lambda(5))
25
25

Результат одинаковый. Разница в том, что def создаёт именованную функцию с телом из нескольких строк, а lambda — одно выражение без имени.

def и lambda — в чём разница?

Критерийdeflambda
ИмяЕстьНет (анонимная)
ТелоЛюбое число строкОдно выражение
returnПишется явноЗначение выражения возвращается само
Логика с if, цикламиДаНет, только выражение
Когда использоватьПереиспользуемая логикаОдноразовая функция как аргумент

Где lambda полезна?

Lambda раскрывается там, где функция нужна один раз и её не имеет смысла выносить в отдельный def. Чаще всего — как аргумент для встроенных функций sorted(), map(), filter().

Сортировка списка словарей по ключу:

users = [
    {"name": "Анна", "age": 25},
    {"name": "Игорь", "age": 19},
    {"name": "Олег", "age": 32},
]

sorted_users = sorted(users, key=lambda user: user["age"])
for u in sorted_users:
    print(u["name"], u["age"])
Игорь 19
Анна 25
Олег 32

Здесь lambda user: user["age"] — это функция, которая извлекает возраст из словаря. sorted() вызывает её для каждого элемента и сортирует по результату. Выносить это в отдельный def — лишний шум, когда логика умещается в одно выражение.

Когда lambda не нужна?

Lambda — не замена обычным функциям. Не используй её, когда...

  • ❌ Логика не умещается в одно выражение. Если нужен if с несколькими ветками или цикл — пиши def.
  • ❌ Функция используется больше одного раза. Именованная функция читается лучше и переиспользуется.
  • ❌ Код становится нечитаемым. Вложенные lambda — это ад для того, кто будет читать код после тебя.
Кот-наставник

— Правило простое: если lambda не помещается в одну короткую строку — это уже не lambda, а def. Читаемость важнее краткости. «Я написал всё в одну строчку» — это не круто.

Частые ошибки при работе с функциями:

1. Забыли return:

def multiply(a, b):
    a * b

result = multiply(3, 4)
print(result)
None

Выражение a * b вычислено, но результат никому не отдан — нет return. Функция вернула None. Правильно: return a * b.

2. Изменяемый аргумент по умолчанию:

def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item("яблоко"))
print(add_item("банан"))
['яблоко']
['яблоко', 'банан']

Сюрприз: второй вызов добавил «банан» к списку, в котором уже было «яблоко». Значение по умолчанию [] создаётся один раз при объявлении функции, а не при каждом вызове. Все вызовы без items используют один и тот же список. Полный разбор этой ловушки — с той же историей для dict и set и с фиксом через None — в статье Изменяемый аргумент по умолчанию в Python: в чём ловушка.

Правильный способ — использовать None и создавать список внутри:

def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item("яблоко"))
print(add_item("банан"))
['яблоко']
['банан']

3. Перепутали порядок аргументов

def power(base, exp):
    return base ** exp

print(power(2, 3))
print(power(3, 2))
8
9

power(2, 3) — это 2 в степени 3 = 8. power(3, 2) — это 3 в степени 2 = 9. Порядок аргументов определяет, какое значение попадёт в какой параметр. Если перепутать — результат будет другим, и ошибка неочевидна.

Рефакторинг: разбиваем программу на функции

Допустим, есть программа — всё в одном потоке, без функций:

name = input("Имя: ")
age = int(input("Возраст: "))
if age < 18:
    print(f"{name}, доступ запрещён")
else:
    print(f"{name}, доступ разрешён")

name2 = input("Имя: ")
age2 = int(input("Возраст: "))
if age2 < 18:
    print(f"{name2}, доступ запрещён")
else:
    print(f"{name2}, доступ разрешён")
Владимир, доступ запрещён
Матвей, доступ разрешён

Один и тот же блок повторяется дважды. Разобьём на функции:

def check_access(name, age):
    if age < 18:
        return f"{name}, доступ запрещён"
    return f"{name}, доступ разрешён"

def ask_user():
    name = input("Имя: ")
    age = int(input("Возраст: "))
    return name, age

name, age = ask_user()
print(check_access(name, age))

name, age = ask_user()
print(check_access(name, age))

Демонстрация недоступна

Код примера изменён, а его трасса выполнения ещё не обновлена.

Каждая функция делает одну вещь: ask_user собирает данные, check_access принимает решение. Если нужно изменить логику проверки — правим check_access. Если нужно изменить формат ввода — правим ask_user. Функции не мешают друг другу.

Кстати, return name, age — это возврат двух значений. Технически Python возвращает кортеж (name, age), а name, age = ask_user() его распаковывает. Подробнее об этом — в статье Списки в Python: создание, методы и срезы, где разбираются кортежи и распаковка.

Короткие ответы на вопросы про функции Python

Чем параметр отличается от аргумента?

Параметр — это переменная в объявлении функции, «ячейка» для данных. Аргумент — конкретное значение, которое передают при вызове. В def greet(name) слово name — параметр, а в вызове greet("Анна") строка "Анна" — аргумент.

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

Функция без return (или с пустым return) возвращает None — специальное значение «ничего». Вывод через print() внутри функции не считается возвратом: он показывает текст на экране, но наружу отдаётся None. Чтобы получить результат для дальнейших вычислений, нужен return.

Что такое lambda-функция простыми словами?

lambda — это функция в одну строку без имени и без def, ограниченная одним выражением. Синтаксис: lambda параметры: выражение. Результат выражения возвращается автоматически. Её используют для коротких одноразовых функций, например как аргумент sorted(), map() или filter().

Зачем нужны *args и **kwargs?

Они позволяют функции принимать переменное число аргументов. *args собирает все лишние позиционные аргументы в кортеж, а **kwargs — все именованные аргументы в словарь. Это удобно, когда заранее неизвестно, сколько значений передадут функции.

Как вернуть из функции несколько значений?

Достаточно перечислить значения после return через запятую: return name, age. Python упакует их в кортеж, а на стороне вызова его можно распаковать сразу в несколько переменных: name, age = ask_user().

Главное про функции:

  1. Функция — именованный блок кода

    Объявляется через def, вызывается по имени со скобками.

    def greet(name):
        print(f"Привет, {name}!")
    
    greet("Анна")
  2. return возвращает результат

    Без return функция возвращает None. return завершает функцию немедленно.

    def add(a, b):
        return a + b
    
    result = add(2, 3)  # 5
  3. Параметры — вход, return — выход

    Функция принимает данные через параметры и отдаёт через return. Не лазий в глобальные переменные.

    counter = 0
    
    def increment(value):
        return value + 1
    
    counter = increment(counter)
  4. Аргументы по умолчанию и именованные

    Упрощают вызов и делают код читаемее.

    def greet(name, greeting="Привет"):
        print(f"{greeting}, {name}!")
    
    greet("Анна")
    greet("Игорь", greeting="Здравствуй")
  5. lambda — для коротких одноразовых функций

    Одно выражение, без def. Не замена обычным функциям.

    sorted_users = sorted(users, key=lambda u: u["age"])
Кот-наставник

— Функции — это первый шаг к осознанному программированию. Не к «выучить синтаксис», а к «мыслить как разработчик»: разбивать задачу на части, давать им имена, собирать из частей целое.

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

Попробуй на практике!

Напиши свою первую функцию — и проследи, как она работает! На SkillPy функции пишешь сам: от простого def до *args и lambda. AI-наставник читает твоё решение, объясняет, почему return важнее print, и показывает, где изменяемый аргумент по умолчанию стреляет в ногу.