Функциональное программирование в Python

Как работает создание и обработка подстрок в Python Программирование и разработка

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

Каковы особенности функционального программирования?

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

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

Функциональное программирование декларативно

При использовании декларативного программирования вы описываете проблему, а поиск решения оставляете на усмотрение локали. Напротив, императивный подход основан на пошаговом описании пути к решению. Функциональное программирование относится к декларативному подходу; Оба подхода можно использовать с Python.

Давайте посмотрим на конкретный пример в Python. Дан список номеров. Мы хотим вычислить соответствующие квадратные числа. Сначала покажем императивный подход :

# Calculate squares from list of numbers
def squared(nums):
  # Start with empty list
  squares = []
  # Process each number individually
  for num in nums:
    squares.append(num ** 2)
  return squares

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

# Numbers 0–9
nums = range(10)
# Calculate squares using list expression
squares = [num ** 2 for num in nums]
# Show that both methods give the same result
assert squares == squared(nums)

Чистые функции предпочтительнее процедур

Чистая функция сравнима с основными математическими функциями. Термин обозначает функцию со следующими свойствами:

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

В совокупности эти свойства означают, что при вызове чистой функции окружающая система не меняется. Рассмотрим классический пример функции квадрата f(x) = x * x. Это можно легко реализовать на Python в виде чистой функции:

# Numbers 0–9
nums = range(10)
# Calculate squares using list expression
squares = [num ** 2 for num in nums]
# Show that both methods give the same result
assert squares == squared(nums)

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

Читайте также:  Как освоить Flask и создать веб-приложение на Python для новичков

В C и Java процедуры реализованы как функции с возвращаемым типом void. В Python функция всегда возвращает значение : если оператор return отсутствует, возвращается специальное значение «Нет». Поэтому, когда мы говорим о процедурах в Python, мы имеем в виду функцию без оператора возврата.

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

# Function without arguments
def get_date():
  from datetime import datetime
  return datetime.now()

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

# Function using non-local value
name = 'John'
def greetings_from_outside():
  return(f"Greetings from {name}")

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

# Function modifying argument
def greetings_from(person):
  print(f"Greetings from {person['name']}")
  # Changing `person` defined somewhere else
  person['greeted'] = True
  return person
# Let's test
person = {'name': "John"}
# Prints `John`
greetings_from(person)
# Data was changed from inside function
assert person['greeted']

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

# Pure function
def squared(num):
  return num * num

Рекурсия используется как альтернатива итерации

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

  1. Рекурсия должна завершиться при достижении базового случая.
  2. При рекурсивном выполнении функции проблема должна быть уменьшена.

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

def fib(n):
  if n == 0 or n == 1:
    return n
  else:
    return fib(n - 2) + fib(n - 1)

Насколько хорош Python для функционального программирования?

Python — мультипарадигмальный язык, т.е. ЧАС. при написании программ можно использовать различные парадигмы программирования. В дополнение к функциональному программированию на Python может быть легко реализовано, в частности, объектно-ориентированное программирование.

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

Читайте также:  Руководство по созданию страницы FAQ при помощи JavaScript - шаг за шагом

Функции в Python — граждане первого класса

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

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

def calculate(a, b, op='+'):
  if op == '+':
    result = a + b
  elif op == '-':
    result = a - b
  elif op == '*':
    result = a * b
  elif op == '/':
    result = a / b
  return result

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

def calculate(a, b, op='+'):
  # Import operator functions
  import operator
  # Map operation symbols to functions
  operations = {
    '+': operator.add,
    '-': operator.sub,
    '*': operator.mul,
    '/': operator.truediv,
  }
  # Choose operation to carry out
  operation = operations[op]
  # Run operation and return results
  return operation(a, b)

Затем мы тестируем нашу декларативную функцию вычисления. Операторы assert показывают, что наш код работает:

# Let's test
a, b = 42, 51
assert calculate(a, b, '+') == a + b
assert calculate(a, b, '-') == a - b
assert calculate(a, b, '*') == a * b
assert calculate(a, b, '/') == a / b

Лямбды — это анонимные функции в Python.

В дополнение к хорошо известному способу определения функций в Python с использованием ключевого слова def, язык знает так называемые «лямбды». Это короткие анонимные (читай: безымянные) функции, определяющие выражение с параметрами. Лямбда-выражения можно использовать везде, где ожидается функция, или присвоить имя:

squared = lambda x: x * x
assert squared(9) == 81

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

def calculate(a, b, op, ops={}):
  # Get operation from dict and define noop for non-existing key
  operation = ops.get(op, lambda a, b: None)
  return operation(a, b)
# Define operations
operations = {
  '+': lambda a, b: a + b,
  '-': lambda a, b: a - b,
}
# Let's test
a, b, = 42, 51
assert calculate(a, b, '+', operations) == a + b
assert calculate(a, b, '-', operations) == a - b
# Non-existing key handled gracefully
assert calculate(a, b, '**', operations) == None
# Add a new operation
operations['**'] = lambda a, b: a ** b
assert calculate(a, b, '**', operations) == a ** b

Функция высшего порядка в Python

Лямбда-выражения часто используются в сочетании с функциями более высокого порядка, такими как map() и filter(). Таким образом, элементы итерируемого объекта могут быть преобразованы без использования циклов. Функция map() принимает функцию и итерируемый объект в качестве параметров и выполняет функцию для каждого элемента итерируемого объекта. Рассмотрим снова задачу генерации квадратных чисел:

nums = [3, 5, 7]
squares = map(lambda x: x ** 2, nums)
assert list(squares) == [9, 25, 49]

Элементы итерируемого объекта могут быть отфильтрованы с помощью функции filter(). Мы расширяем наш пример, чтобы генерировались только четные квадратные числа:

nums = [1, 2, 3, 4]
squares = list(map(lambda num: num ** 2, nums))
even_squares = filter(lambda square: square % 2 == 0, squares)
assert list(even_squares) == [4, 16]

Итерации, включения и генераторы

Итерации — это основная концепция Python. Это абстракция коллекций, элементы которых можно выводить по отдельности. К ним относятся вы. Строки, кортежи, списки и словари — все по одним и тем же правилам. Например, область действия итерируемого объекта можно запросить с помощью функции len():

name = 'Walter White'
assert len(name) == 12
people = ['Jim', 'Jack', 'John']
assert len(people) == 3

Понимания используются на основе итерируемых объектов. Они хорошо подходят для функционального программирования и в значительной степени заменили использование лямбда-выражений с помощью map() и filter().

# List comprehension to create first ten squares
squares = [num ** 2 for num in range(10)]

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

# Generator expression to create first ten squares
squares = (num ** 2 for num in range(10))

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

def N(limit):
  n = 1
  while n <= limit:
    yield n
    n += 1

Какие альтернативы Python существуют для функционального программирования?

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

Читайте также:  "Полное руководство по отправке файлов в ASP.NET Core"

Чисто функциональные языки с сильными системами типов, такие как Haskell или диалект Lisp Clojure, особенно сильны. С другой стороны, JavaScript также считается функциональным языком. С TypeScript доступна современная альтернатива со строгой типизацией.

Оцените статью
Блог о программировании
Добавить комментарий