Рубріки: Теория

Просто про функции и их аргументы в Python

Семен Гринштейн

Функции существуют в большинстве современных языков программирования. В императивных языках (к которым относится и Python) функция — это набор инструкций, объединенных для выполнения одной задачи. Блоки кода, однажды оформленные в виде функций, можно использовать в коде многократно. Поэтому разработчики охотно применяют этот подход на практике, чтобы облегчить работу себе и своему приложению.

Редакция highload.today разобралась, как это работает, как создавать функции Python, на какие разновидности они делятся, как вызывать функции и передавать в них аргументы. Теперь мы готовы помочь разобраться в этом вам. И… да, примеры кода обязательно будут.

Содержание:
1. Что такое функция в Python
2. Именные функции (инструкция def)
3. Документирование функции
4. Аргументы функции
5. Инструкция return
6. Глобальные и локальные переменные
7. Рекурсивные функции
8. Анонимные функции (инструкция lambda)
9. Присвоение функции переменной
Заключение

1. Что такое функция в Python

В предыдущем абзаце уже шла речь о том, что функции Python делятся на разновидности. Мы рассмотрим две классификации:

  1. встроенные / не встроенные (пользовательские);
  2. именные / без имени (анонимные).

Отличия между ними сводятся не только к синтаксису и способу использования. Не менее важно, что работают они тоже по-разному (далее мы в этом убедимся).

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

Встроенная функция Python Краткое описание
len() вычисляет длину (количество элементов) последовательности (например, списка)
next() возвращает следующий по порядку элемент последовательности (например, списка)
reversed() меняет порядок элементов последовательности на обратный

В языке Python десятки таких функций, и внутренняя реализация многих из них очень сложна. Но об этом за вас уже позаботились разработчики языка, поэтому пользуйтесь с удовольствием — как говорится, бесплатно и без регистрации. Разобраться во всех тонкостях языка Python можно на специальных курсах от наших партнеров в Powercode и ШАГ.

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

  • разделить объемный код на понятные, осмысленные части;
  • вынести повторяющийся код в один блок;
  • оптимизировать скорость работы приложения.

Про встроенные функции Python в этой статье мы говорить практически не будем, но знайте, что они есть. И перед тем, как писать свою функцию, проверьте, существует ли встроенная функция, которая подходит для решения вашей задачи.

2. Именные функции (инструкция def)

Из названия термина ясно, что синтаксис такой функции обязательно должен включать ее имя:

def function_name(parameters):
    """здесь можно описать, что делает функция"""
    statement(s)
return result

Первая строка — заголовок функции. Далее следуют опциональная строковая переменная (в тройных кавычках) и тело функции (обозначено как statement(s)).

У синтаксиса функции есть ряд особенностей:

  1. Заголовок функции должен начинаться с ключевого слова def.
  2. Функция должна иметь уникальное имя (уникальное внутри определенных областей видимости — о них расскажем позже).
  3. В функцию для обработки можно передать произвольное количество параметров. Но это необязательно.
  4. Заголовок функции обязательно должен заканчиваться двоеточием.
  5. Между тройными кавычками можно написать, что делает функция (об этом поговорим в другом разделе).
  6. Тело функции — это тот самый набор инструкций, объединенных для общей задачи. Туда и надо писать код, отвечающий за всю логику работы функции.
  7. Описательную переменную с тройными кавычками и все инструкции внутри тела нужно располагать со смещением в 4 пробела от слова def — по горизонтали вправо.
  8. По итогам работы функции с помощью инструкции return можно вернуть результат — в виде числа или списка например. Но это необязательно.

Функции Python могут иметь произвольное имя. Но желательно, чтобы имя было глаголом и отражало суть задачи, которую решает эта функция.

Пример:

def greet(name):
    """  Функция выводит приветственное сообщение для имени name """
    print("Hello, " + name + ". Good morning!")

Напомним также общие правила именования переменных, которые полностью распространяются и на имена функций:

  1. Имя может состоять из чисел, латинских символов и символа нижнего подчеркивания и не должно включать что-либо другое.
  2. Имя функции не должно включать пробелы.
  3. В начале имени нельзя ставить цифру.
  4. X и x — это два разных идентификатора (регистр имеет значение).
  5. Имена функций рекомендуют начинать со строчной буквы.
  6. В качестве имени пользовательской функции запрещено использовать ключевые слова языка Python и имена его встроенных функций.

Вызов функции

Функцию можно вызвать из консоли Python, из скрипта или из другой функции. Чтобы сделать это для именной функции мы должны написать ее имя, а в скобках при необходимости передать ей параметры, либо оставить скобки пустыми.

>>> say_goodbye('Paul')
Goodbye, Paul.

вызов функции из консоли Python

def say_goodbye(name):
        print("Goodbye, " + name)

say_goodbye('Paul')

вызов функции say_goodbye из скрипта Python и вызов функции print из функции say_goodbye

ВАЖНО: язык Python не позволяет вызывать функцию до того, как она была создана. Потому что анализатор Python в данном случае сканирует код сверху вниз и не может найти объявление функции, которая была вызвана.

# вызов функции
say_goodbye('Paul')

# реализация функции
def say_goodbye(name):
        print("Goodbye, " + name)

# Ошибка: в точке say_goodbye('Paul') функция 'say_goodbye' не определена, не существует

вызов функции до ее объявления

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

Источник: www.programiz.com

3. Документирование функции

После заголовка функции идет опциональная строка, в которой можно написать любой текст. Но в данном случае она нужна для описания, документирования работы функции. Ее еще называют иностранным словосочетанием docstring. Вряд ли вы помните, что делает и как работает каждая функция, которую вы написали. Если даже вы это помните, то остальные разработчики, которые будут сопровождать или как-то еще использовать ваш код, не в курсе.

Поэтому такое документирование позволяет в итоге сэкономить время. А те минуты, которые вы потратите на него, окупятся с избытком.

Вспомним функцию из предыдущего примера и добавим в нее docstring:

def greet(name):
    """  Функция выводит приветственное сообщение для имени name """
    print("Hello, " + name + ". Good morning!")

объявление функции с документированием

Все, теперь, встретившись с таким кодом, другие разработчики сразу поймут, что к чему. Понятно, что тут очень простой пример, но представьте, что это большой и запутанный код.

Но оказывается, можно сделать жизнь разработчиков еще проще. Встретив функцию, они могут не искать ее объявление по всему проекту, а воспользоваться специальным атрибутом __doc__.

>>> print(greet.__doc__)

    Функция выводит приветственное сообщение для имени name

вывод значения атрибута __doc__ для функции greet

4. Аргументы функции

def function_name(parameters):

Вновь вернемся к заголовку функции и разберемся, какими могут быть эти самые параметры, они же — аргументы. Сколько их может быть? В предельном случае их может не быть вовсе. Тогда получаем такой заголовок:

def function_name():

и вот такой вызов функции:

function_name();

Рассмотрим теперь более распространенный случай, когда аргументов несколько.

def say_goodbye(name, msg):
    print("Goodbye", name + ', ' + msg)

say_goodbye("Monica", "Sweet dreams!")

Функция say_goodbye принимает два аргумента — переменные name и msg. Вызывая функцию, мы передаем в нее значения, которые соответствуют аргументам. То есть эти значения (“Monica” и “Sweet dreams!“) подставляются вместо переменных name и msg соответственно.

Результат работы программы:

Goodbye Monica, Sweet dreams!

Отлично. Два аргумента — два переданных значения. Все работает.

Но что будет, если мы передадим в эту же функцию только одно значение или совсем не передадим значения?

>>> say_goodbye("Monica")    
TypeError: say_goodbye() missing 1 required positional argument: 'msg'

>>> say_goodbye()    
TypeError: say_goodbye() missing 2 required positional arguments: 'name' and 'msg'

Как видите программа работать не будет и выдаст ошибку для каждого вызова. Получается, Python не позволяет передавать количество значений, не совпадающее с количеством аргументов, указанных в объявлении функции?

Если отвечать в очень грубом приближении, то не позволяет. Но далее мы увидим, как можно решить эту задачу, если очень хочется.

Значения аргументов по умолчанию

Python позволяет задавать значения аргументов по умолчанию.

def say_goodbye(name, msg="Sweet dreams!"):

    print("Goodbye", name + ', ' + msg)

Конструкция msg="Sweet dreams!" в первой строке означает, что при вызове функции значение аргумента msg можно не задавать. Достаточно задать только значение аргумента name, а значение msg подставится само.

say_goodbye("Monica")

И тогда программа будет работать без ошибок:

Goodbye Monica, Sweet dreams!

При этом вариант вызова с полным количеством аргументов также будет работать

say_goodbye("Bruce", "See you!")

и программа выдаст

Goodbye Bruce, See you!

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

Однако, в силу особенностей языка Python, мы не можем переписать код так:

def say_goodbye(msg = "Sweet dreams!", name):

Потому что получим ошибку.

SyntaxError: non-default argument follows default argument

Это означает, что справа от аргумента со значением по умолчанию могут располагаться только такие же аргументы, имеющие значение по умолчанию. Обычные аргументы без значений по умолчанию должны находиться слева.

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

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

Вот такой код

say_goodbye("See you!", "Bruce")

приведет к следующему результату:

Goodbye See you!, Bruce

Потому что в объявлении функции аргументы расположены не в том порядке:

def say_goodbye(name, msg):

В Python такие аргументы называются позиционными. Но существуют и аргументы другого типа — именованные или ключевые (калька с английского keyword arguments). Если точнее, то существует другой способ передачи значений аргументов при вызове функции.

# 2 ключевые аргументы
say_goodbye(name = "Bruce", msg = "See you!")

# 2 ключевые аргументы в другом порядке
say_goodbye(msg = "See you!",name = "Bruce") 

Такая конструкция позволяет игнорировать порядок передачи аргументов при вызове функции. Хотя можно использовать и смешанный вариант:

# позиционный и ключевой аргумент
say_goodbye("Bruce", msg = "See you!")      

Функции с неизвестным количеством аргументов

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

def say_goodbye(*names):
    """Функция выведет приветствие для каждого
имени из полученного names"""
                
    for name in names:
        print("Goodbye", name)

В этом случае перед именем списка пишется знак *. Тут names — это список имен неизвестной длины. Функция обрабатывает его, как обычный список.

Вызывая эту функцию, мы можем в качестве аргументов передавать произвольное количество значений. Они преобразуются в список и полученный список автоматически подставляется вместо переменной names.

say_goodbye("Monica", "Luke", "Steve", "John")

Результат работы программы:

Goodbye Monica
Goodbye Luke
Goodbye Steve
Goodbye John

5. Инструкция return

Несмотря на то, что эта инструкция опциональная, она помогает в двух случаях:

  • Когда нужно вернуть результат работы функции в виде значения, которое может использовано вне функции — например, записано во внешнюю переменную.
def sum(a,b):
return a+b
  • Когда нужно прервать работу функции и вернуться к той точке программы, из которой была вызвана эта функция.
def division(a,d):
    if d == 0:    # если делитель равен нулю
    return "Нельзя делить на ноль"  # мы прерываем работу функции

    return a / d

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

print(sum(2, 4))
print(sum(2, -4))

Получим

6
-2

print(division(4, 2))
print(division(4, 0))

Получим

2.0
Нельзя делить на ноль

Если в коде функции нет инструкции return, она не возвращает ничего. Запустив в консоли функцию из предыдущего раздела, в третьей строке мы получим None.

>>> print(say_goodbye("May"))
Goodbye, May. 
None

6. Глобальные и локальные переменные

В этой статье мы еще не встречали функции, в которых помимо аргументов использованы переменные. Например:

def multiplicator(x):
    k = 2
    return k * x

Что это за переменная k?

Чтобы ответить на этот вопрос, нужно ввести понятия области видимости и времени жизни переменных. Область видимости переменной — это фрагмент программы (блок), внутри которого эта переменная существует и доступна. О такой переменной говорят, что она видна в данной области видимости (простите за тавтологию).

В приведенном выше примере переменная k видна только внутри функции. В этом случае говорят, что переменная является локальной.

Время жизни переменной — это временной промежуток, в течение которого переменная хранится в памяти (и доступна хотя бы для чтения).

Локальные переменные обычно живут до тех пор, пока функция не завершит свою работу после очередного вызова. Во время каждого вызова функции все ее локальные переменные сбрасываются и инициализируются заново. Значения (если они были изменены) локальных переменных из предыдущих вызовов функция не хранит.

Хорошо, тогда что будет, если создать переменную с тем же именем, но за пределами функции?

def multiplicator(x):
    k = 2
print("Значение локальной переменной k:", k)
    return k*x

k = 20
multiplicator(4)
print("Значение внешней переменной k:", k)

А вот что:

Значение локальной переменной k: 2
Значение внешней переменной k: 20

В этом примере внешняя переменная k никак не влияет на результат работы функции. Дело в том, что сначала функция ищет переменную с подходящим именем внутри своей локальной области видимости — где как раз находится локальная переменная k.

Если мы удалим эту переменную из реализации функции, то она будет искать k уже во внешних по отношению к ней блоках кода (пошагово двигаясь изнутри наружу). В данном случае она найдет внешнюю переменную k, равную 20 и использует ее значение для своих вычислений.

Но если нам нужно не просто использовать, а еще и модифицировать это значение, необходимо внести изменения в код:

def multiplicator(x):
    global k
k = 2
print("Значение локальной переменной k:", k)
    return k*x

k = 20
multiplicator(4)
print("Значение внешней переменной k:", k)

Добавив выделенные жирными строки (global k и k = 2), мы сообщаем анализатору Python, что не намерены создавать локальную переменную k: мы просто модифицируем глобальную переменную.

Язык программирования Python – один из самых востребованных. С каждым годом потребность в специалистах с его знаниями только растет. Поэтому если вам он интересен, то вы можете записаться на курс к нашим друзьям из академии ШАГ или Mate Academy. Получите высокооплачиваемую профессию на долгие годы.

7. Рекурсивные функции

В разделе про python def function мы упоминали, что функцию можно вызывать, находясь внутри другой функции. Оказывается, функция может вызывать саму себя внутри своего же исходного кода.

def factorial(x):
    #условие окончания рекурсии
    if x == 1:
        return 1
    else:
        return (x * factorial(x-1))

num = 3
print("Факториал числа", num, "равен", factorial(num))

Такие функции называют рекурсивными. В данном случае factorial(x) один раз вызывается из внешней программы и два раза — из самой себя. Перед каждым из двух этих вызовов значение аргумента x уменьшается на 1. Это происходит до тех пор, пока x не достигнет значения, равного 1. Это так называемое условие окончания рекурсии.

Программа отработает и выведет соответствующее сообщение:

Факториал числа 3 равен 6

Последовательность вычислений можно представить в хронологическом порядке:

Операция Значение x Состояние программы Условие окончания рекурсии
factorial(3) 3 первый вызов функции не выполнено
3 * factorial(2) 2 второй вызов, погружение в рекурсию не выполнено
3 * (2 * factorial(1)) 1 третий вызов, погружение в рекурсию не выполнено
3 * (2 * 1) 1 выход из рекурсии (всплываем) выполнено
return 3 * 2 2 выход из рекурсии выполнено
6 3 возвращение результата выполнено

8. Анонимные функции (инструкция lambda)

Их также называют лямбда-функциями (это отсылка к математическому инструментарию под названием Лямбда Исчисление). Ключевое отличие анонимных от именных функций, казалось бы, заложено в их названиях. Но это не совсем так.

Во-первых, синтаксис функций отличается кардинально:

lambda аргументы: выражение

Во-вторых, лямбда-функция может выполнить только одну инструкцию (действие).

Для чего тогда нам нужны такие узкоспециализированные функции?

Анонимные функции идеально подходят, если нужно передать функцию в другую функцию в качестве аргумента. И если больше нигде переданная функция не будет вызвана — имя ей не понадобится. Ну и требование выполнять только одно действие (вычислять лишь одно выражение) здесь тоже играет в плюс, так как делает код более лаконичным.

Пример 1:

l = [2, 5, 1, 4]
l.sort(key=lambda x: x)

Результат работы

[1, 2, 4, 5]

Пример 2:

l = [2, 5, 1, 4]
l.sort(key=lambda x: -x)

Результат работы

[5, 4, 2, 1]

В первом примере список будет отсортирован по своим исходным (не измененным) значениям. Во втором примере лямбда-функция подставит вместо каждого элемента списка это же число, но со знаком минус. В результате список будет отсортирован в обратном порядке.

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

9. Присвоение функции переменной

Присвоение анонимной функции

Будет очень в тему еще один пример с анонимной функцией:

double = lambda x: x * 2

В данном случае мы просто присвоили имя этой лямбда-функции, но не вызвали ее. Этот код эквивалентен вот такой реализации именной функции:

def double(x):
print(x * 2)
return x * 2

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

double(3)

Присвоение именной функции

Хорошо, а какие чудеса мы сможем сотворить, если запишем в переменную именную функцию? Для примера создадим вот такую функцию:

def f():
print("I am f")

Зададимся целью ввести такую переменную g, чтобы

  • g() запускал вызов функции f
  • с печатью строки I am f

Первый способ

def f():
    print("I am f")


# присваивание
g = f
# вызов функции
g()

Это работает, потому что благодаря присваиванию переменная g указывает на тот же участок памяти (блок кода), что и функция f. А значит, подставив к g скобки, мы получим обычный вызов функции.

Второй способ

Используем так называемую лямбда-обертку. Создадим лямбда-функцию без аргументов, с возвращаемым значением в виде f() и запишем ее в переменную g (примерно так мы делали в начале раздела).

def f():
    print("I am f")

# лямбда-обертка
g = lambda : f()
# вызов функции
g()

Это будет работать так же, так как лямбда-функция, записанная в переменную g запустится (то есть отправит на выполнение инструкцию f()) только после выполнения инструкции g()

Заключение

Функции Python — это достаточно гибкий механизм, но в нем легко запутаться, не зная тонкостей. Надеюсь, в этой статье нам удалось заложить основы и объяснить важные детали при работе с функциями. Но если у вас остались вопросы, или вы хотите более подробно вникнуть в язык программирования Python, то курсы наших друзей Hillel и Powercode, помогут вам освоить новые знания.

Видео: примеры использования функции map()

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023