Course

Функции — неотъемлемая часть языка программирования Python: вы наверняка уже встречались и пользовались множеством замечательных встроенных функций Python или функций из библиотек его экосистемы. Однако как дата-сайентист вам постоянно придётся писать собственные функции, чтобы решать задачи, которые ставят перед вами данные.
В этом руководстве используется синтаксис Python 3. Все примеры работают на Python 3.10+ и обновлены с учётом современных соглашений (f-строки, подсказки типов, параметры только позиционные и только по ключу). Текущий стабильный релиз — Python 3.14.
Чтобы легко запустить весь пример кода из этого руководства самостоятельно, вы можете бесплатно создать рабочую тетрадь DataLab с предустановленным Python и всеми образцами кода. Для дополнительной практики по написанию функций в Python загляните в это практическое упражнение DataCamp или пройдите наш курс Python Data Science Toolbox!
Функции в Python
В программировании вы используете функции, чтобы объединить набор инструкций, которые вы хотите многократно применять, или которые из-за своей сложности лучше изолировать в подпрограмме и вызывать по мере необходимости. Иными словами, функция — это фрагмент кода, написанный для выполнения конкретной задачи. Для её выполнения функция может требовать один или несколько входов, а может и не требовать. По завершении задачи функция может возвращать одно или несколько значений либо ничего не возвращать.
В Python есть три типа функций:
-
Встроенные функции, такие как
help()для получения справки,min()для нахождения минимального значения,print()для вывода объекта в терминал и т. д. Обзор таких функций можно найти здесь. -
Пользовательские функции (UDF), то есть функции, которые пользователи создают для своих задач; и
-
Анонимные функции, которые также называют лямбда-функциями, поскольку они объявляются не с помощью стандартного ключевого слова
def.
Функции и методы
Метод — это функция, являющаяся частью класса. Доступ к нему осуществляется через экземпляр или объект класса. Функции такого ограничения не имеют: это самостоятельные функции. То есть все методы — это функции, но не все функции — методы.
Рассмотрим пример, где вы сначала определяете функцию plus(), а затем класс Summation с методом sum():
Если теперь вы хотите вызвать метод sum(), который является частью класса Summation, вам сначала нужно создать экземпляр или объект этого класса. Давайте создадим такой объект:
Помните, что такая инициализация не нужна, когда вы хотите вызвать функцию plus()! Вы сможете выполнить plus(1,2) в блоке кода DataCamp Light без каких-либо проблем!
Параметры и аргументы
Параметры — это имена, используемые при определении функции или метода, к которым сопоставляются аргументы. Иными словами, аргументы — это значения, которые передаются при вызове функции или метода, а код функции или метода обращается к этим значениям по именам параметров.
Рассмотрите следующий пример и вернитесь к блоку DataCamp Light выше: вы передаёте два аргумента методу sum() класса Summation, хотя ранее определили три параметра: self, a и b.
Что произошло с self?
Первый аргумент каждого метода класса — это всегда ссылка на текущий экземпляр класса, в данном случае Summation. По соглашению этот аргумент называется self.
Это означает, что вы не передаёте ссылку на self явно, поскольку self — это имя параметра для неявно передаваемого аргумента, ссылающегося на экземпляр, через который вызывается метод. Он вставляется в список аргументов автоматически.
Как определить функцию: пользовательские функции (UDF)
Четыре шага для определения функции в Python:
-
Используйте ключевое слово
defдля объявления функции и укажите имя функции. -
Добавьте параметры функции: они должны быть в круглых скобках. Завершите строку двоеточием.
-
Добавьте инструкции, которые должна выполнять функция.
-
Завершите функцию оператором return, если функция должна что-то вернуть. Без оператора return функция вернёт объект
None.
Конечно, по мере продвижения ваши функции будут становиться сложнее: вы можете добавлять циклы for, управляющие конструкции и многое другое, чтобы сделать их более тонкими:
def hello():
name = input("Enter your name: ")
if name:
print(f"Hello {name}")
else:
print("Hello World")
hello()
В приведённой выше функции вы просите пользователя ввести имя. Если имя не задано, функция выведет «Hello World». В противном случае пользователь получит персонализированное «Hello».
Помните, что вы можете определить один или несколько параметров функции для своей UDF. Вы узнаете больше об этом в разделе «Аргументы функции». Кроме того, вы можете возвращать одно или несколько значений как результат работы функции либо ничего не возвращать.
Оператор return
Обратите внимание: так как в вашей UDF hello() происходит вывод с помощью print, возвращать значение не обязательно. Разницы между функцией выше и этой не будет:
Однако, если вы хотите дальше работать с результатом функции и пробовать над ним операции, нужно использовать оператор return, чтобы действительно вернуть значение, например строку, целое число и т. п. Рассмотрим сценарий, где hello() возвращает строку "hello", а функция hello_noreturn() возвращает None:
Вторая функция выдаст ошибку, потому что с None нельзя выполнять операции. Вы получите TypeError с сообщением, что нельзя выполнить операцию умножения для NoneType (того самого None, который возвращает hello_noreturn()) и int (2).
Совет: функции немедленно завершают выполнение при встрече оператора return, даже если при этом они ничего не возвращают:
Ещё один момент, который стоит упомянуть при работе с оператором return: с его помощью можно возвращать несколько значений. Для этого используются кортежи.
Помните, что эта структура данных очень похожа на список: она может содержать несколько значений. Однако кортежи неизменяемы, то есть вы не можете изменять значения, хранящиеся в них! Они создаются с помощью парных круглых скобок (). Кортежи можно распаковывать в несколько переменных с помощью запятой и оператора присваивания.
Посмотрите следующий пример, чтобы понять, как функция может возвращать несколько значений:
Замечание: оператор return с записью return sum, a даст тот же результат, что и return (sum, a): в первом случае sum и a под капотом упаковываются в кортеж!
Как вызывать функцию
В предыдущих разделах вы уже видели множество примеров того, как можно вызывать функцию. Вызвать функцию — значит выполнить определённую вами функцию — либо напрямую из интерактивной оболочки Python, либо из другой функции (как вы увидите в разделе «Вложенные функции»).
Вызовите вашу новую функцию hello(), просто выполнив hello(), как в блоке DataCamp Light ниже:
Как добавить docstring к функции Python
Ещё один важный аспект написания функций в Python: docstring. Docstring описывает, что делает ваша функция: какие вычисления выполняет или какие значения возвращает. Эти описания служат документацией функции, чтобы любой, кто прочитает docstring, понял назначение функции, не просматривая весь её код.
Docstring функции размещается сразу после заголовка функции и заключается в тройные кавычки. Подходящий docstring для вашей функции hello() — «Печатает “Hello World”».
def hello() -> None:
"""Prints "Hello World"."""
print("Hello World")
Замечание: docstring может быть и намного длиннее приведённого примера. Если вы хотите изучить docstring подробнее, лучше посмотреть репозитории Python-библиотек на Github, таких как scikit-learn или pandas — там вы найдёте множество примеров!
Подсказки типов
Тесно связаны с docstring — и почти так же распространены в современном Python-коде — подсказки типов. Начиная с Python 3.5, вы можете аннотировать параметры функции и возвращаемое значение ожидаемыми типами. Вот самый простой пример:
def plus(a: int, b: int) -> int:
return a + b
Запись : int после каждого параметра означает «ожидается целое число», а -> int после скобок — «эта функция возвращает целое число». Сам Python не применяет эти аннотации во время выполнения — вы всё ещё можете передать строку в plus(), и Python не пожалуется, пока что-то не сломается. Но инструменты вроде mypy, pyright и средства проверки типов, встроенные в редакторы вроде VS Code и PyCharm, используют эти подсказки, чтобы ловить ошибки ещё до запуска кода.
Для более сложных типов можно использовать встроенные дженерики напрямую (Python 3.9+) или импортировать из модуля typing:
def greet(names: list[str]) -> None:
for name in names:
print(f"Hello {name}")
def find_user(user_id: int) -> dict | None:
# returns the user dict, or None if not found
...
Аргументы функций в Python
Ранее вы узнали о различии между параметрами и аргументами. Коротко: аргументы — это то, что передаётся в любой вызов функции или метода, а код функции или метода обращается к аргументам по именам параметров. Пользовательские функции Python могут принимать четыре типа аргументов:
- Аргументы по умолчанию
- Обязательные аргументы
- Именованные аргументы
- Произвольное число аргументов
Аргументы по умолчанию
Аргументы по умолчанию получают значение по умолчанию, если при вызове функции значение аргумента не передано. Назначить значение по умолчанию можно с помощью оператора присваивания =, как в примере ниже:
Обязательные аргументы
Как видно из названия, обязательные аргументы UDF — это те, которые должны присутствовать. Эти аргументы нужно передавать при вызове функции и в строго правильном порядке, как в примере ниже:
Чтобы вызвать функцию без ошибок, вам нужны аргументы, которые сопоставятся параметрам a и b. Если поменять местами a и b, результат не изменится, но он может измениться, если вы измените plus() следующим образом:
Именованные аргументы
Если вы хотите быть уверены, что указываете все параметры в правильном порядке, используйте именованные аргументы при вызове функции. С их помощью вы сопоставляете аргументы с параметрами по имени. Возьмём приведённый выше пример для наглядности:
Обратите внимание: с именованными аргументами вы также можете менять порядок параметров и всё равно получать тот же результат при выполнении функции:
Произвольное число аргументов
Если вы не знаете точного числа аргументов, которые хотите передать функции, используйте следующую запись с *args:
Звёздочка (*) ставится перед именем переменной, которая содержит значения всех позиционных неименованных аргументов. Заметьте, что вы могли бы так же передать *varint, *var_int_args или любое другое имя в функцию plus().
Совет: попробуйте заменить *args на другое имя со звёздочкой. Вы увидите, что код выше продолжит работать!
Вы видите, что функция выше использует встроенную функцию Python sum() для суммирования всех аргументов, переданных в plus().
Глобальные и локальные переменные
Обычно переменные, определённые внутри тела функции, имеют локальную область видимости, а определённые снаружи — глобальную. Это значит, что локальные переменные определены в блоке функции и доступны только внутри неё, тогда как глобальные переменные доступны всем функциям в вашем скрипте:
Вы увидите, что при попытке вывести локальную переменную total, определённую внутри тела функции, вы получите NameError с сообщением name 'total' is not defined. Переменная init, напротив, будет выведена без проблем.
Параметры только позиционные и только по ключу
Начиная с Python 3.8, вы можете жёстче контролировать способ передачи аргументов с помощью двух специальных маркеров в сигнатуре функции: / и *. Всё, что перед /, можно передавать только позиционно; всё, что после *, — только по ключу.
def greet(name, /, greeting="Hello", *, punctuation="!"):
print(f"{greeting} {name}{punctuation}")
Вот как это работает при вызове:
greet("Alice") # works
greet("Alice", greeting="Hi") # works
greet("Alice", "Hi", punctuation="?") # works
greet(name="Alice") # TypeError: name is positional-only
greet("Alice", "Hi", "?") # TypeError: punctuation is keyword-only
Зачем это нужно? Две основные причины.
Во-первых, параметры только позиционные позволяют переименовывать их в будущем, не ломая чужой код — так как никто не может использовать имя параметра как ключевое слово, вы свободны его менять.
Во-вторых, параметры только по ключу заставляют вызывающую сторону быть явной в том, что она передаёт, что повышает читаемость вызовов, когда у вас несколько необязательных флагов или настроек.
Проще говоря, это чистый способ зафиксировать намерения.
Анонимные функции в Python
Анонимные функции в Python также называют лямбда-функциями, потому что вместо стандартного ключевого слова def используется ключевое слово lambda.
В блоке DataCamp Light выше lambda x: x*2 — это анонимная, или лямбда-функция. x — аргумент, а x*2 — выражение или инструкция, которая вычисляется и возвращается. Особенность этой функции в том, что у неё нет имени, в отличие от примеров из первой части этого руководства по функциям. Если бы вы написали эту функцию как UDF, получилось бы следующее:
def double(x):
return x*2
Рассмотрим другой пример лямбда-функции с двумя аргументами:
Анонимные функции используют, когда вам нужна безымянная функция на короткое время, создаваемая во время выполнения. Конкретные контексты, где это полезно, — работа с filter(), map() и reduce():
Функция filter(), как и подсказывает название, фильтрует исходный список my_list на основе критерия >10. С map(), напротив, вы применяете функцию ко всем элементам списка my_list. В этом случае вы умножаете все элементы на 2.
Обратите внимание: функция reduce() находится в библиотеке functools. Её применяют к элементам списка my_list накопительно слева направо, сводя последовательность к одному значению — в данном случае 55.
Использование main() как функции в Python
Если у вас есть опыт с другими языками программирования, такими как Java, вы знаете, что функция main обязательна для выполнения кода. Как вы видели в примерах выше, для Python это не обязательно. Однако включение функции main() в программу Python помогает логично структурировать код — все самые важные компоненты будут находиться внутри этой функции main().
Вы можете легко определить функцию main() и вызвать её так же, как делали с другими функциями выше:
Однако в текущем виде код вашей функции main() будет выполняться при импорте её как модуля. Чтобы этого не происходило, вызывайте функцию main(), когда __name__ == '__main__'.
Это означает, что код из блока выше станет таким:
Замечание: помимо __main__, существует также функция __init__, которая инициализирует экземпляр класса или объект. Проще говоря, она выступает в роли конструктора/инициализатора и автоматически вызывается при создании нового экземпляра класса. С её помощью только что созданный объект присваивается параметру self, с которым вы уже знакомы по этому руководству. Посмотрите на следующий пример:
class Dog:
"""A simple Dog class.
Args:
legs: Number of legs so that the dog can walk.
color: The color of the fur.
"""
def __init__(self, legs: int, color: str) -> None:
self.legs = legs
self.color = color
def bark(self) -> str:
return "bark" * 2
if __name__ == "__main__":
dog = Dog(4, "brown")
print(dog.bark())
Продолжайте практиковаться с функциями Python
Поздравляем! Вы прошли это короткое руководство по функциям в Python. Если хотите повторить другие базовые материалы по программированию на Python, не пропустите курс Data Types for Data Science, где вы закрепите и попрактикуете знания о списках, словарях, кортежах, множествах и датах и времени.
Часто задаваемые вопросы о функциях Python
Что такое функция в Python?
Функция — это переиспользуемый блок кода, выполняющий конкретную задачу. Она может принимать входные данные, обрабатывать их и возвращать результаты.
Как определить функцию в Python?
Чтобы определить функцию в Python, используйте ключевое слово def, укажите имя функции, добавьте необязательные параметры в скобках, напишите код и при необходимости верните значение с помощью return.
В чём разница между функциями и методами в Python?
Функции существуют сами по себе, а методы принадлежат классам. Все методы — функции, но не все функции — методы.
Какие бывают типы функций в Python?
В Python есть встроенные функции (например, print()), пользовательские функции (ваши собственные) и анонимные функции (краткие функции lambda).
В чём разница между параметрами и аргументами?
Параметры — это заполнители в определении функции, а аргументы — фактические значения, которые вы передаёте при вызове.
Что такое лямбда-функция?
Лямбда-функция — это однострочная, безымянная функция для быстрых задач.
Зачем использовать функцию __main__?
Функция __main__ помогает организовать код и гарантирует, что определённые части выполняются только при непосредственном запуске скрипта, а не при импорте.
В чём разница между глобальными и локальными переменными?
Глобальные переменные доступны везде, а локальные живут только внутри своей функции.