3.1 Знайомство з замиканнями
Замикання — це функція, яка захоплює змінні з своєї оточуючої області видимості, навіть після того, як ця область завершила своє виконання. Це означає, що замикання може «пам'ятати» значення змінних з своєї зовнішньої області видимості і продовжувати працювати з ними, навіть коли ця область більше не активна.
Щоб зрозуміти, як працюють замикання, розгляньмо наступний приклад:
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
closure = outer_function(10)
print(closure(5)) # Вивід: 15
Давайте розберемо, що тут написано:
Зовнішня функція (outer_function): Ця функція приймає аргумент x і визначає внутрішню функцію inner_function, яка приймає аргумент y і повертає суму x і y. Функція inner_function не викликається всередині outer_function, а тільки оголошується.
Внутрішня функція (inner_function): Ця функція повертається з outer_function і зберігає в собі посилання на значення x, яке було передано outer_function.
Замикання: Змінна closure стає замиканням, яке «пам'ятає» значення x (в даному випадку, 10) і може використовувати його при виклику.
Зазвичай ніхто з першого разу не може нормально працювати з замиканнями. Тож давайте спробуємо прокачати ваше розуміння замикань на прикладах.
3.2 Приклади використання замикань
Створення функції-генератора
Замикання можуть бути використані для створення функцій-генераторів, які генерують послідовності значень.
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
counter = make_counter()
print(counter()) # Вивід: 1
print(counter()) # Вивід: 2
print(counter()) # Вивід: 3
Пояснення:
Функція-генератор (make_counter): Ця функція створює змінну count і повертає внутрішню функцію counter, яка збільшує значення count і повертає його.
Замикання: Функція counter зберігає стан змінної count і може змінювати його при кожному виклику.
Створення функції з конфігурацією
Замикання можуть бути використані для створення функцій з попередньо визначеною конфігурацією.
def make_multiplier(factor):
def multiplier(x):
return x * factor
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # Вивід: 10
print(triple(5)) # Вивід: 15
Пояснення:
Функція-конфігуратор (make_multiplier): Ця функція приймає множитель factor і повертає внутрішню функцію multiplier, яка множить вхідне значення на factor.
Замикання: Функції double і triple є замиканнями, які зберігають свої власні значення factor і використовують їх для множення.
Фільтрація даних з параметрами
Замикання можуть бути корисні для створення фільтруючих функцій з параметрами.
def make_filter(threshold):
def filter_func(value):
return value > threshold
return filter_func
filter_above_10 = make_filter(10)
data = [5, 10, 15, 20]
filtered_data = list(filter(filter_above_10, data))
print(filtered_data) # Вивід: [15, 20]
Пояснення:
Функція-фільтр (make_filter): Ця функція приймає порогове значення threshold і повертає внутрішню функцію filter_func, яка перевіряє, чи перевищує значення поріг.
Замикання: Функція filter_func зберігає значення threshold і використовує його для фільтрації даних.
3.3 Плюси і мінуси замикань
Переваги використання замикань
Інкапсуляція стану: Замикання дозволяють інкапсулювати стан в функції, уникаючи глобальних змінних і покращуючи читабельність та підтримку коду.
Гнучкість: Замикання можуть бути використані для створення функцій з певною конфігурацією або поведінкою, що робить код більш гнучким і адаптованим.
Функціональне програмування: Замикання є важливою концепцією в функціональному програмуванні, дозволяючи створювати функції вищого порядку та інші функціональні конструкції.
Обмеження та потенційні проблеми
Попри багато переваг, замикання мають і свої обмеження:
Використання пам'яті: Замикання можуть утримувати посилання на об'єкти, які більше не використовуються, що може призвести до витоків пам'яті.
Складність відладки: Замикання можуть ускладнити відладку коду, оскільки стани змінних можуть бути неочевидними.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ