Функции в Python: def, аргументы и return
Функции в Python: объявление через def, return, аргументы по умолчанию, *args и **kwargs, область видимости, встроенные функции и функциональный стиль.
Содержание · 11 разделов
- Как объявить и вызвать функцию: def
- return: что возвращает функция
- Аргументы функции
- Позиционные, именованные и значения по умолчанию
- *args и **kwargs
- Полная сигнатура
- Область видимости: локальные и глобальные переменные
- Аннотации типов и docstring
- Функции — это объекты: функциональное программирование на Python
- Встроенные функции Python
- Рекурсия
- Частые ошибки
- Функция без скобок
- print вместо return
- Изменяемое значение по умолчанию
- Неверное число аргументов
- Имя переменной перекрыло встроенную функцию
- Частые вопросы
- Изменится ли список, если передать его в функцию?
- Как создать пустую функцию-заготовку?
- Можно ли вызвать функцию до её объявления?
- Как узнать, какие аргументы принимает функция?
- Чем функция отличается от метода?
- Итог
Функции в Python объявляются ключевым словом def: после него идут имя, список параметров в скобках и двоеточие, а тело функции пишется с отступом. Результат возвращается через return. Короткий ответ:
def greet(name):
return f"Привет, {name}!"
message = greet("Анна")
print(message) # → Привет, Анна!
Функция позволяет один раз описать действие и вызывать его сколько угодно раз с разными данными. Ниже — как работают return и аргументы (*args, **kwargs, значения по умолчанию), где видны переменные, что такое встроенные функции Python и как функции используются в функциональном стиле программирования. Примеры проверены на Python 3.12.
Как объявить и вызвать функцию: def
def area(width, height):
"""Вернуть площадь прямоугольника."""
return width * height
print(area(3, 4)) # → 12
print(area(2.5, 2)) # → 5.0
print(area.__doc__) # → Вернуть площадь прямоугольника.
Разберём по частям:
widthиheight— параметры: имена, под которыми функция получает данные. Значения3и4при вызове — аргументы.- Строка в тройных кавычках сразу после
def— docstring, описание функции. Его показываютhelp(area)и подсказки редактора. - Имена функций по PEP 8 пишут в
snake_case:get_user,calculate_total.
Функция выполняется только при вызове — когда после имени стоят скобки: area(3, 4). Объявление def лишь создаёт объект функции.
return: что возвращает функция
return завершает функцию и передаёт значение туда, откуда её вызвали. Можно вернуть несколько значений через запятую — Python упакует их в кортеж, который удобно распаковать:
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([7, 2, 9, 4])
print(low, high) # → 2 9
print(min_max([1, 5])) # → (1, 5)
Если return нет или он написан без значения, функция возвращает None:
def say_hi(name):
print("Привет,", name)
result = say_hi("Олег") # → Привет, Олег
print(result) # → None
return можно использовать для раннего выхода — код после него не выполняется:
def safe_div(a, b):
if b == 0:
return None
return a / b
print(safe_div(10, 4)) # → 2.5
print(safe_div(1, 0)) # → None
Как строить такие проверки, подробно разобрано в статье об условиях if, elif, else.
Аргументы функции
Позиционные, именованные и значения по умолчанию
def make_order(item, qty=1, *, express=False):
kind = "экспресс" if express else "обычная"
return f"{item} × {qty}, доставка {kind}"
print(make_order("кофе")) # → кофе × 1, доставка обычная
print(make_order("чай", 3)) # → чай × 3, доставка обычная
print(make_order(qty=2, item="сок")) # → сок × 2, доставка обычная
print(make_order("кофе", express=True)) # → кофе × 1, доставка экспресс
- Позиционные аргументы сопоставляются с параметрами по порядку, именованные — по имени, и их порядок не важен.
qty=1— значение по умолчанию: аргумент можно не передавать.- Всё, что стоит после одиночной
*, передаётся только по имени. Вызовmake_order("кофе", 1, True)вызоветTypeError: make_order() takes from 1 to 2 positional arguments but 3 were given. Так флаги вродеexpressне перепутать с количеством.
*args и **kwargs
*args собирает лишние позиционные аргументы в кортеж, **kwargs — лишние именованные в словарь. Имена args и kwargs — соглашение, важны только звёздочки:
def total(*prices):
return sum(prices)
print(total(100, 250, 40)) # → 390
print(total()) # → 0
def build_url(base, **params):
query = "&".join(f"{k}={v}" for k, v in params.items())
return f"{base}?{query}" if query else base
print(build_url("/search", q="django", page=2)) # → /search?q=django&page=2
Звёздочки работают и в обратную сторону — при вызове они распаковывают список или словарь в аргументы:
size = [3, 4]
print(area(*size)) # → 12, то же что area(3, 4)
print(area(**{"width": 5, "height": 2})) # → 10
Полная сигнатура
Параметры до / передаются только позиционно, после * — только по имени. Порядок в объявлении всегда такой:
def f(a, b, /, c, *args, d, e=0, **kwargs):
print(a, b, c, args, d, e, kwargs)
f(1, 2, 3, 4, 5, d=6, x=7) # → 1 2 3 (4, 5) 6 0 {'x': 7}
f(1, 2, c=3, d=4) # → 1 2 3 () 4 0 {}
| Вид параметра | Синтаксис | Как передаётся |
|---|---|---|
| Только позиционный | a, / | только по порядку |
| Обычный | c | по порядку или по имени |
| Со значением по умолчанию | e=0 | можно не передавать |
| Произвольные позиционные | *args | лишние позиционные → кортеж |
| Только именованный | *, d | только как d=... |
| Произвольные именованные | **kwargs | лишние именованные → словарь |
Область видимости: локальные и глобальные переменные
Переменные, созданные внутри функции, локальны: снаружи их не видно. Читать глобальную переменную внутри функции можно, а чтобы присвоить ей новое значение, нужно объявить её global:
counter = 0
def show():
print("внутри:", counter)
def increment():
global counter
counter += 1
show() # → внутри: 0
increment()
print("снаружи:", counter) # → снаружи: 1
Без global строка counter += 1 внутри функции делает counter локальной переменной и падает с UnboundLocalError: cannot access local variable 'counter' where it is not associated with a value. На практике глобальные переменные лучше не менять из функций, а передавать данные через параметры и return.
Для вложенных функций есть nonlocal — он позволяет изменить переменную объемлющей функции. Так устроено замыкание: внутренняя функция «помнит» окружение, в котором была создана:
def make_counter():
count = 0
def step():
nonlocal count
count += 1
return count
return step
c = make_counter()
print(c(), c(), c()) # → 1 2 3
На замыканиях построены декораторы в Python.
Аннотации типов и docstring
Аннотации описывают ожидаемые типы параметров и результата:
def average(values: list[float], digits: int = 2) -> float:
"""Среднее арифметическое, округлённое до digits знаков."""
return round(sum(values) / len(values), digits)
print(average([4, 5, 5])) # → 4.67
Python не проверяет аннотации во время выполнения: double("ab") для функции с аннотацией x: int спокойно вернёт 'abab'. Аннотации читают редакторы, анализаторы вроде mypy и библиотеки — например, Pydantic и FastAPI строят на них валидацию данных.
Функции — это объекты: функциональное программирование на Python
Функцию можно положить в переменную, передать в другую функцию, вернуть из функции или сохранить в словаре:
def shout(text):
return text.upper() + "!"
def whisper(text):
return text.lower() + "..."
def apply(func, value):
return func(value)
print(apply(shout, "привет")) # → ПРИВЕТ!
handlers = {"громко": shout, "тихо": whisper}
print(handlers["тихо"]("Спокойной ночи")) # → спокойной ночи...
В apply(shout, ...) функция передаётся без скобок — передаём сам объект, а не результат вызова. На этом держится аргумент key у sorted(), min() и max(): sorted(words, key=len) сортирует слова по длине.
Функциональный стиль в Python строится на трёх приёмах: функциях высшего порядка (map, filter, functools.reduce), коротких анонимных функциях и отказе от изменения данных на месте:
from functools import reduce
nums = [1, 2, 3, 4, 5, 6]
print(list(map(lambda n: n * n, nums))) # → [1, 4, 9, 16, 25, 36]
print(list(filter(lambda n: n % 2 == 0, nums))) # → [2, 4, 6]
print(reduce(lambda acc, n: acc * n, nums)) # → 720
print([n * n for n in nums if n % 2 == 0]) # → [4, 16, 36]
Последняя строка — генератор списка: в Python он часто читается проще, чем связка map и filter. Безымянные функции lambda разобраны в отдельной статье о lambda-функциях, а map() — в статье о функции map. Для углублённого изучения подойдёт короткая книга Дэвида Мерца «Functional Programming in Python» (O’Reilly, на английском языке), другие книги собраны в подборке книг по Python.
Встроенные функции Python
Встроенные функции доступны без import. Самые нужные:
| Функция | Что делает | Пример → результат |
|---|---|---|
print(), input() | вывод и ввод | input("Имя: ") → строка |
len() | длина коллекции или строки | len([3, -7, 12]) → 3 |
int(), float(), str() | преобразование типов | int("42") → 42 |
sum(), min(), max() | сумма, минимум, максимум | max([3, -7, 12]) → 12 |
abs(), round() | модуль, округление | round(3.14159, 2) → 3.14 |
sorted() | новый отсортированный список | sorted([3, 0, -7]) → [-7, 0, 3] |
range() | последовательность чисел | list(range(3)) → [0, 1, 2] |
enumerate(), zip() | номер элемента, параллельный обход | list(zip("ab", [1, 2])) → [('a', 1), ('b', 2)] |
map(), filter() | применить функцию, отфильтровать | см. раздел выше |
any(), all() | хотя бы один / все элементы истинны | all(n < 20 for n in [3, 12]) → True |
type(), isinstance() | тип объекта, проверка типа | isinstance([], list) → True |
help(), dir() | справка и список атрибутов объекта | help(len) |
Полный список — в документации по встроенным функциям. Подробно о двух из них: range() и enumerate().
Рекурсия
Функция может вызывать саму себя. Главное — условие выхода, иначе вызовы не закончатся:
def factorial(n):
if n <= 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # → 120
По умолчанию глубина рекурсии ограничена (sys.getrecursionlimit() возвращает 1000), при превышении возникает RecursionError. Для обхода больших данных обычно надёжнее цикл.
Частые ошибки
Функция без скобок
def greet():
return "Привет"
print(greet) # → <function greet at 0x...>
print(greet()) # → Привет
Без скобок вы получаете сам объект функции, а не результат её работы.
print вместо return
def add(a, b):
print(a + b)
result = add(2, 3) # → 5
print(result * 2) # → TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'
print() только выводит значение на экран, а функция без return возвращает None. Если результат нужен дальше в программе — возвращайте его.
Изменяемое значение по умолчанию
def add_item(item, cart=[]):
cart.append(item)
return cart
print(add_item("кофе")) # → ['кофе']
print(add_item("чай")) # → ['кофе', 'чай'] — список общий!
Значение по умолчанию вычисляется один раз при объявлении функции, поэтому список копится между вызовами. Используйте None:
def add_item(item, cart=None):
if cart is None:
cart = []
cart.append(item)
return cart
Неверное число аргументов
area(3) для def area(width, height) даёт TypeError: area() missing 1 required positional argument: 'height', а area(3, 4, 5) — TypeError: area() takes 2 positional arguments but 3 were given. Сверьте вызов с сигнатурой функции.
Имя переменной перекрыло встроенную функцию
После list = [1, 2, 3] вызов list("abc") падает с TypeError: 'list' object is not callable. Не называйте переменные list, dict, str, sum, max и другими именами встроенных функций.
Частые вопросы
Изменится ли список, если передать его в функцию?
Да, если функция меняет сам объект: append(), remove(), присваивание по индексу. Python передаёт в функцию ссылку на объект, а не копию. Новое присваивание параметру внутри функции на исходный список не влияет:
def add_zero(prices):
prices.append(0) # меняет исходный список
prices = [p * 2 for p in prices] # новый локальный список
return prices
items = [100, 200]
add_zero(items)
print(items) # → [100, 200, 0]
Если исходные данные менять нельзя, работайте с копией: prices = list(prices).
Как создать пустую функцию-заготовку?
Тело функции не может быть пустым, поэтому в нём пишут pass или многоточие .... Такая функция возвращает None:
def todo():
pass
print(todo()) # → None
Можно ли вызвать функцию до её объявления?
Нет: def выполняется сверху вниз, как любая другая инструкция, и до этой строки имени функции не существует. Вызов раньше объявления даёт NameError: name 'hello' is not defined. При этом внутри другой функции можно ссылаться на функцию, объявленную ниже, если вызов произойдёт после того, как обе будут объявлены.
Как узнать, какие аргументы принимает функция?
help(имя_функции) показывает сигнатуру и docstring, а inspect.signature() возвращает сигнатуру как объект:
import inspect
def make_order(item, qty=1, *, express=False): ...
print(inspect.signature(make_order)) # → (item, qty=1, *, express=False)
В VS Code и PyCharm та же подсказка появляется при наведении на имя функции.
Чем функция отличается от метода?
Метод — это функция, объявленная внутри класса. Его вызывают через объект: text.upper(), items.append(3), и первым аргументом он неявно получает сам объект (self). Обычную функцию вызывают по имени: len(text). Подробнее — в статье о классах.
Итог
Функция объявляется через def, получает данные через параметры и отдаёт результат через return; без return она возвращает None. Значения по умолчанию, *args, **kwargs и keyword-only параметры делают вызовы гибкими, а то, что функции — обычные объекты, открывает дорогу к lambda, map и декораторам. Остальной базовый синтаксис — в шпаргалке по синтаксису Python, а следующий шаг после функций — классы и ООП.
- #Python
- #Функции
- #def
- #return
- #Синтаксис