Замыкания Python
Замыкания Python
В этом руководстве вы узнаете о замыкании Python, о том, как определить замыкание и почему вам следует его использовать.
Нелокальная переменная во вложенной функции
Прежде чем перейти к тому, что такое замыкание, мы должны сначала понять, что такое вложенная функция и нелокальная переменная.
Функция, определенная внутри другой функции, называется вложенной функцией. Вложенные функции могут обращаться к переменным внешней области.
В Python эти нелокальные переменные по умолчанию доступны только для чтения, и мы должны явно объявить их как нелокальные (используя ключевое слово nonlocal), чтобы изменить их.
Ниже приведен пример вложенной функции, обращающейся к нелокальной переменной.
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")
Вывод
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()
Вывод
Hello
Это необычно.
print_msg()
функция была вызвана со строкой "Hello"
и возвращаемая функция была привязана к имени another . При вызове 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 at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)
Объект ячейки имеет атрибут cell_contents, в котором хранится закрытое значение.
>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5
Python