Функції вищого порядку
Ще одним принциповим положенням функційного програмування є функції вищого порядку.
Функції як об'єкти
Вже не раз згадувалось, що "в Python усе є об'єкт". І функції тут не вийняток.
>>> def f():
... pass
...
>>> f
<function f at 0x000002877927F0D0>
>>> type(f)
<class 'function'>
>>>
Тобто функції — це об'єкти, які належать до класу function
.
Об'єкт першого класу
Об'єкт називають «об'єктом першого класу», якщо:
- його може бути збережено у змінній або інших структурах даних;
- його може бути передано в функцію як аргумент;
- його може бути поверненим з функції як результат;
- його може бути створено під час виконання програми;
- він внутрішньо самоідентифікується (не залежить від іменування).
Зауважте що термін «об'єкт» використовується тут у загальному розумінні і не обмежується об'єктами мови програмування.
В Python функції — об'єкти першого класу.
Посилання на функції
При оголошенні функції створюється об'єкт класу function
,
і паралельно створються змінна з іменем,
вказаним після def
.
Пам'ятаючи, що змінні в Python — не що інше, як посилання на об'єкти,
ми легко можемо посилатися на функцію за допомогою іншого імені:
>>> def original():
... print("It work's")
...
>>> original()
It work's
>>> copy = original
>>> copy
<function original at 0x000002877927F158>
>>> copy()
It work's
>>>
Зауважте що об'єкт класу function
має своє ім'я.
Давайте напишемо примітивний калькулятор який буде підтримувати усього чотири арифметичні операції. Нехай користувач вводить два операнди і операцію над ними, а програма виводить результат.
def add(a, b):
return a + b
def sub(a, b):
return a - b
def mul(a, b):
return a * b
def div(a, b):
return a / b
operators = {
'+': add,
'-': sub,
'*': mul,
'/': div,
}
n1 = float(input('Enter first operand: '))
op = input('Enter operator: ')
n2 = float(input('Enter second operand: '))
res = operators[op](n1, n2)
print('Result', res)
Функції вищого порядку
Функція вищого порядку — це така функція, яка приймає іншу функцію в якості аргумента та/або повертає іншу функцію.
>>> def f(x):
... return x + 3
...
>>> def g(function, x):
... return function(x) * function(x)
...
>>> g(f, 7)
100
>>>
У наведеному вище прикладі g()
— функція вищого порядку.
Функції як аргументи
Для початку давайте розглянемо ще одну вбудовану функцію Python:
sorted(iterable, key=None, reverse=False)
Функція повертає список який складається з відсортованих елементів послідовності iterable
.
Необов'язкові аргументи:
key
— функція з одним параметром. Цій функції будуть передаватись елементиiterable
. Функція має повертати "ключ" сортування, тобто ті значення, по яким буде відбуватись порівняння елементівiterable
. За замовчуванням дорівнюєNone
, тобто усі елементи порівнюються "напряму".reverse
— типуbool
. ЯкщоTrue
, то елементи послідовності будуть відсортовані у зворотньому порядку.
Простий приклад: маємо список символьних рядків, який треба відсортувати.
>>> l = ['John', 'jam', 'Jane', 'job']
>>> sorted(l)
['Jane', 'John', 'jam', 'job']
>>>
Отримали відсортований список рядків. Зауважте, що символьні рядки відсортовані у лексиграфічному порядку, тобто при порівнюванні рядкків між собою враховувався регістр букв (верхній чи нижній).
А тепер припустимо, що нам потрібно відсортувати список символьних рядків не враховуючи регістр останніх. Найпростіше — приводити усі символьні рядки до одного регістру перед тим як порівнювати їх між собою.
Отже функції sorted()
можна передати як аргумент ще одну функцію,
яка у свою чергу буде трошки "змінювати" наші символьні рядки.
Визначимо останню:
>>> def to_lower(string):
... return string.lower()
...
>>>
І тепер передаємо її у якості аргументу:
>>> sorted(l, key=to_lower)
['jam', 'Jane', 'job', 'John']
>>>