Замикання в Python – це вкладена функція, яка дозволяє отримати доступ до змінних зовнішньої функції навіть після завершення виконання зовнішньої функції. Перш ніж ми поговоримо про замикання, спочатку розглянемо концепцію вкладених функцій в Python.
Вкладені функції в Python
В Python ми можемо створити функцію всередині іншої функції — це називається вкладеною функцією. Наприклад:
|
1 2 3 4 5 6 7 8 9 10 |
def greet(name): # Внутрішня функція def display_name(): print("Hi", name) # Виклик внутрішньої функції display_name() # Виклик зовнішньої функції greet("John") |
Результат:
Hi John
Тут ми визначили функцію display_name() всередині функції greet(). Функція display_name() є вкладеною функцією. Вкладена функція працює аналогічно до звичайної функції.
Замикання в Python
Замикання — це вкладена функція, яка допомагає отримати доступ до змінних зовнішньої функції навіть після завершення виконання зовнішньої функції. Наприклад:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
def greet(): # Змінна, визначена поза внутрішньою функцією name = "John" # Повертаємо вкладену анонімну функцію return lambda: "Hi " + name # Виклик зовнішньої функції message = greet() # Виклик внутрішньої функції print(message()) |
Результат:
Hi John
Тут ми створили функцію greet(), яка повертає вкладену анонімну функцію. Коли ми викликаємо зовнішню функцію:
|
1 |
message = greet() |
Результат її виконання присвоюється змінній message.
На цьому виконання зовнішньої функції завершено, і змінна name має бути знищена. Однак, коли ми викликаємо анонімну функцію, використовуючи:
|
1 |
print(message()) |
Ми можемо отримати доступ до змінної name зовнішньої функції (навіть після того, як вона завершила своє виконання).
Це можливо через те, що вкладена функція тепер діє як замикання, яке закриває змінну всередині своєї області видимості навіть після завершення виконання зовнішньої функції.
Розглянемо ще один приклад замикання в Python. Програма для виводу непарних чисел:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def calculate(): num = 1 def inner_func(): nonlocal num num += 2 return num return inner_func # Виклик зовнішньої функції odd = calculate() # Виклик внутрішньої функції print(odd()) print(odd()) print(odd()) # Знову виклик зовнішньої функції odd2 = calculate() print(odd2()) |
Результат:
3
5
7
3
Наступний рядок коду виконує зовнішню функцію calculate() та повертає замикання змінної num:
|
1 |
odd = calculate() |
Саме тому ми можемо отримати доступ до змінної num з функції calculate() навіть після завершення її виконання.
Знову ж таки, коли ми викликаємо зовнішню функцію, використовуючи:
|
1 |
odd2 = calculate() |
Повертається нове замикання. Отже, при виклику функції odd2() ми отримуємо значення 3.
Коли використовуються замикання?
Замикання можуть використовуватися для того, щоб уникнути використання глобальних змінних та забезпечити приховування даних. Вони можуть бути елегантним рішенням для простих випадків з одним чи кількома методами.
Однак для випадків з великою кількістю атрибутів і методів може бути краща реалізація класу.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def make_multiplier_of(n): def multiplier(x): return x * n return multiplier # Множник 3 times3 = make_multiplier_of(3) # Множник 5 times5 = make_multiplier_of(5) # Вивід значень print(times3(9)) print(times5(3)) print(times5(times3(2))) |
Результат:
27
15
30
Підбиваючи підсумки, хотілося б відзначити, що значення, поміщені у функцію-замикання, можна дізнатися. Усі об’єкти функцій мають атрибут __closure__, який повертає кортеж об’єктів, якщо функція є замиканням. Посилаючись на вищенаведений приклад, ми знаємо, що times3 і times5 є функціями-замиканнями.

(12 оцінок, середня: 4,58 з 5)