Функція вищого порядку (англ. Higher-Order Function, HOF) – це функція, яка може приймати інші функції як аргументи та/або повертати функцію як результат.
Розглянемо простий приклад функції вищого порядку process_number():
def process_number(value, func):
return func(value)
def multiply(x):
return x * x
def power(x):
return x**x
def add(x):
return x + x
def subtract(x):
return x - (x * x)
print(process_number(5, multiply)) # 25
print(process_number(3, power)) # 27
print(process_number(10, add)) # 20
print(process_number(4, subtract)) # -12Вбудовані функції вищого порядку Python
Python надає вбудовані функції вищого порядку, такі як map() та filter(), які спрощують роботу з об’єктами ітераторами.
Функція map() приймає функцію та ітерований об’єкт (наприклад список), і застосовує цю функцію до кожного його елемента, після чого повертає об’єкт ітератор що містить результати:
users = [
{'name': 'Alice', 'email': 'alice@example.com'},
{'name': 'Bob', 'email': 'bob@example.com'},
{'name': 'Charlie', 'email': 'charlie@example.com'},
]
def format_email(user):
return f"{user['name']} <{user['email']}>"
formatted_emails = map(format_email, users)
print(list(formatted_emails))
# ['Alice <alice@example.com>', 'Bob <bob@example.com>', 'Charlie <charlie@example.com>']Також можна використовувати lambda функцію, як аргумент функції map(). Приклад:
numbers = [1, 2, 3, 4, 5]
squares = map(lambda x: x**2, numbers)
print(list(squares))
# [1, 4, 9, 16, 25]Функція filter() приймає функцію-предикат та об’єкт ітератор, проходить по кожному елементу і повертає новий ітератор, що складається тільки з тих елементів, для яких функція-предикат повернула True:
def is_even(x):
return x % 2 == 0
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = filter(is_even, numbers)
print(list(even_numbers))
# [2, 4, 6]Приклад з використанням lambda:
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))
# [2, 4, 6]Функція яка повертає функцію
Функції вищого порядку можуть повертати інші функції. Це особливо корисно, коли потрібно створити функцію з наперед визначеними параметрами або поведінкою, залежно від зовнішнього контексту. Приклад:
def greeting_builder(language):
def greet(name):
if language == 'en':
return f'Hello, {name}!'
elif language == 'uk':
return f'Привіт, {name}!'
elif language == 'es':
return f'¡Hola, {name}!'
else:
return f'Hi, {name}!'
return greet
# Створюємо функції з фіксованою мовою
english_greeting = greeting_builder('en')
ukrainian_greeting = greeting_builder('uk')
# Використання
print(english_greeting('Alice')) # Hello, Alice!
print(english_greeting('Jhon')) # Hello, Jhon!
print(ukrainian_greeting('Олег')) # Привіт, Олег!Застосування функцій вищого порядку
Функції вищого порядку мають широке застосування у таких напрямках як функціональне програмування, замикання та декоратори.
Замикання
Замикання (closure) – це функція, яка запам’ятовує змінні з лексичного оточення, в якому була створена, навіть після завершення виконання зовнішньої функції:
- це вкладена функція, тобто функція визначена всередині іншої функції
- внутрішня функція має доступ до змінних зовнішньої функції
- зовнішня функція повертає внутрішню функцію як результат
Зазвичай після завершення роботи функції її локальні змінні видаляються з пам’яті. Але якщо внутрішня функція, яка була створена всередині неї та повернена, продовжує посилатися на ці змінні, утворюється замикання, яке зберігає ці змінні доступними навіть після завершення зовнішньої функції.
Приклад функції лічильника:
def counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
click_counter = counter()
print(click_counter()) # 1
print(click_counter()) # 2
print(click_counter()) # 3Це зручно, коли потрібно зберігати певний стан між викликами функції, без використання класів або глобальних змінних.
Декоратори
Декоратори Python – це елегантний спосіб модифікувати або розширювати функціональність функцій (або методів), без зміни їх вихідного коду. Декоратор є функцією вищого порядку, яка приймає іншу функцію як аргумент, додає до неї нову поведінку та повертає модифіковану функцію.
Приклад:
def logger(func):
def wrapper(*args, **kwargs):
print(f'Calling function: {func.__name__}')
return func(*args, **kwargs)
return wrapper
@logger
def say_hello(name):
print(f'Hello, {name}!')
say_hello('Alice')
# Calling function: say_hello
# Hello, Alice!