У цьому підручнику ви дізнаєтесь про закриття Python, як визначити закриття та причини, за якими слід ним користуватися.
Нелокальна змінна у вкладеній функції
Перш ніж з’ясувати, що таке закриття, ми повинні спочатку зрозуміти, що таке вкладена функція та нелокальна змінна.
Функція, визначена всередині іншої функції, називається вкладеною функцією. Вкладені функції можуть отримувати доступ до змінних охоплюючої області дії.
У Python ці нелокальні змінні за замовчуванням доступні лише для читання, і ми повинні явно оголосити їх як нелокальні (з використанням нелокального ключового слова), щоб їх змінити.
Далі наведено приклад вкладеної функції, яка отримує доступ до нелокальної змінної.
def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) printer() # We execute the function # Output: Hello print_msg("Hello")
Вихідні дані
Здравствуйте
Ми бачимо, що вкладена printer()
функція змогла отримати доступ до нелокальної змінної msg функції, що включає.
Визначення функції закриття
У наведеному вище прикладі, що сталося б, якби останній рядок функції print_msg()
повернув printer()
функцію, а не викликав її? Це означає, що функція була визначена наступним чином:
def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) return printer # returns the nested function # Now let's try calling this function. # Output: Hello another = print_msg("Hello") another()
Вихідні дані
Здравствуйте
Це незвично.
print_msg()
Функція була викликана рядком "Hello"
і повертається функція була пов'язана з ім'ям іншого. Під час дзвінка another()
повідомлення все ще запам'ятовувалось, хоча ми вже завершили виконання print_msg()
функції.
Цей прийом, за допомогою якого деякі дані ( "Hello
у даному випадку) приєднуються до коду, називається закриттям в Python .
Це значення в області, що охоплює, запам'ятовується, навіть коли змінна виходить за межі області дії або сама функція видаляється з поточного простору імен.
Спробуйте запустити наступне в оболонці Python, щоб побачити результати.
>>> del print_msg >>> another() Hello >>> print_msg("Hello") Traceback (most recent call last):… NameError: name 'print_msg' is not defined
Тут повернута функція все ще працює, навіть коли вихідну функцію було видалено.
Коли у нас закриття?
Як видно з наведеного вище прикладу, у нас є закриття в Python, коли вкладена функція посилається на значення у своїй обширній області.
Критерії, яким необхідно відповідати для створення закриття в Python, зведені в наступних пунктах.
- У нас повинна бути вкладена функція (функція всередині функції).
- Вкладена функція повинна посилатися на значення, визначене у функції, що включає.
- Функція, що включає, повинна повертати вкладену функцію.
Коли застосовувати закриття?
То для чого корисні закриття?
Закриття дозволяє уникнути використання глобальних значень і забезпечує певну форму приховування даних. Він також може надати об'єктно-орієнтоване рішення проблеми.
Коли в класі існує декілька методів (у більшості випадків - один метод), закриття може запропонувати альтернативне та більш елегантне рішення. Але коли кількість атрибутів і методів збільшується, краще реалізувати клас.
Ось простий приклад, коли закриття може бути кращим, ніж визначення класу та створення об’єктів. Але уподобання все ваше.
def make_multiplier_of(n): def multiplier(x): return x * n return multiplier # Multiplier of 3 times3 = make_multiplier_of(3) # Multiplier of 5 times5 = make_multiplier_of(5) # Output: 27 print(times3(9)) # Output: 15 print(times5(3)) # Output: 30 print(times5(times3(2)))
Вихідні дані
27 15 30
Декоратори Python також широко використовують закриття.
На завершальному етапі варто зазначити, що значення, які вкладаються у функцію закриття, можна дізнатись.
Усі об’єкти функції мають __closure__
атрибут, який повертає кортеж об’єктів комірки, якщо це функція закриття. Посилаючись на приклад вище, ми знаємо times3
і times5
є функціями закриття.
>>> make_multiplier_of.__closure__ >>> times3.__closure__ (,)
Об’єкт комірки має атрибут cell_contents, який зберігає закрите значення.
>>> times3.__closure__(0).cell_contents 3 >>> times5.__closure__(0).cell_contents 5