- Что такое детерминированность
- Что такое побочные эффекты
- Что такое чистые функции
- Что такое грязные функции
- Выводы
Часто в программировании возникает проблема с неявными зависимостями и побочными эффектами. Они могут привести к неожиданным результатам или ошибкам в программе. Обычно с такими проблемами борются с помощью чистых функций.
В этом уроке мы изучим важные свойства функций. С их помощью можно более точно определять, как лучше разбивать код на функции и когда вообще их стоит выделять.
Что такое детерминированность
Детерминированность функций — это свойство, при котором функция всегда возвращает один и тот же результат для одних и тех же входных данных без побочных эффектов, связанных с состоянием программы. Детерминированная функция не зависит от контекста и внешних факторов. Она гарантированно возвращает предсказуемый результат.
Рассмотрим пример функции, которая не является детерминированной:
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()
выводит переданный ей аргумент и возвращает его. Это также может привести к неожиданным результатам в виде излишнего вывода на экран.
Выводы
Чистые и грязные функции имеют разные особенности и применения.
Чистые функции являются более предпочтительными. Они проще для понимания и тестирования, а также могут быть использованы в многопоточных приложениях без каких-либо проблем.
Грязные функции могут быть полезными в некоторых случаях, например, когда нужно изменить состояние программы или выполнить ввод-вывод. Но такие функции могут усложнить отладку и тестирование приложения.
Рекомендуем использовать чистые функции, когда это возможно. А использование грязных функций лучше ограничить. Их стоит применять только для тех случаев, когда это действительно необходимо.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Вебинар «Как самостоятельно учиться»
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.