Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Чистые функции Python: Функции

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

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

Что такое детерминированность

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

Рассмотрим пример функции, которая не является детерминированной:

import random

def get_random_number():
    return random.randint(1, 10)

Эта функция возвращает случайное число от 1 до 10 при каждом вызове. Если мы вызываем функцию несколько раз, то получим разные результаты:

get_random_number()
# 3
get_random_number()
# 7
get_random_number()
# 1

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

def multiply(a, b):
    return a * b

Функция multiply всегда возвращает результат умножения двух переданных ей аргументов. Если мы передадим одни и те же значения, то получим один и тот же результат:

multiply(2, 3)
# 6
multiply(2, 3)
# 6
multiply(2, 3)
# 6

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

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

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

Что такое побочные эффекты

Побочный эффект или side effects — это любые взаимодействия с внешней средой. Они включают в себя изменения глобальных переменных и операции с файлами. Например, запись в файл, чтение из файла, отправка или прием данных по сети и вывод в консоль.

Рассмотрим пример функции, которая имеет побочный эффект:

def print_hello():
    print("Hello, world!")

Эта функция выводит сообщение в консоль, значит, она имеет побочный эффект. Если мы вызываем функцию print_hello, то она изменяет состояние программы путем вывода сообщения в консоль. Но она не возвращает никакого значения:

print_hello()
# Hello, world!

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

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

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

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

Что такое чистые функции

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

Признаки чистых функций:

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

Примеры чистых функций в Python:

def add_numbers(x, y):
    return x + y

def multiply_numbers(x, y):
    return x * y

def is_even(x):
    return x % 2 == 0

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

У чистых функций есть несколько преимуществ:

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

Что такое грязные функции

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

Рассмотрим несколько примеров.

Функции, которые изменяют глобальные переменные

count = 0

def increment():
    global count
    count += 1
    return count

increment()  # 1
increment()  # 2
count        # 2

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

Функции, которые изменяют аргументы

def append_list(my_list, element):
    my_list.append(element)
    return my_list

a = [1, 2, 3]
append_list(a, 4)  # [1, 2, 3, 4]
a                  # [1, 2, 3, 4]

В примере функция append_list() добавляет элемент в конец переданного ей списка my_list. Это часто приводит к ошибкам в расчетах в других частях программы.

Функции, которые работают с файлами

def write_file(text):
    with open("test.txt", "w") as file:
        file.write(text)

write_file("Hello, world!")

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

Функции, которые имеют побочный эффект вывода на экран

def print_and_return(value):
    print(value)
    return value

print_and_return(10)
# 10
# 10

В данном примере функция print_and_return() выводит переданный ей аргумент и возвращает его. Это также может привести к неожиданным результатам в виде излишнего вывода на экран.

Выводы

Чистые и грязные функции имеют разные особенности и применения.

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

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

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


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 6 300 ₽ в месяц
Разработка веб-приложений на Django
10 месяцев
с нуля
Старт 2 мая

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»