Ответ
Замыкание (closure) — это функция, которая "помнит" и имеет доступ к переменным из своей лексической области видимости, даже когда исполнение этой области завершено.
Как это работает:
Когда вложенная функция ссылается на переменную из внешней функции (не являющуюся её локальной переменной), Python связывает эту переменную с вложенной функцией. Эта связь сохраняется в специальном атрибуте __closure__.
Три условия для создания замыкания:
- Должна существовать вложенная функция.
- Вложенная функция должна ссылаться на переменные из внешней функции (так называемые "свободные переменные").
- Внешняя функция должна возвращать вложенную функцию.
Пример:
def outer_func(text):
# 'text' - это свободная переменная для inner_func
def inner_func():
# inner_func "замыкает" в себе переменную text
print(text)
return inner_func
# Вызываем внешнюю функцию, она завершает работу,
# но возвращенная inner_func все еще помнит 'text'
printer_hello = outer_func("Hello")
printer_world = outer_func("World")
# Вызываем экземпляры вложенной функции
printer_hello() # Вывод: Hello
printer_world() # Вывод: World
# Можно проверить содержимое __closure__
# Это кортеж из объектов-ячеек (cell), хранящих значения
print(printer_hello.__closure__[0].cell_contents) # Вывод: Hello
Практическое применение:
- Декораторы: Являются самым частым и ярким примером использования замыканий.
- Фабрики функций: Создание функций с предопределенной конфигурацией (как в примере выше).
- Сохранение состояния: Реализация объектов с состоянием без использования классов, например, для создания счетчиков или кэширования.
Ответ 18+ 🔞
А, слушай, смотри, вот эта штука — замыкание. Ну, типа, функция, которая, блядь, помнит всё, что было вокруг неё, даже когда всё уже давно кончилось и разъехалось. Как будто она в кармане унесла кусочек того места, где её родили, сука.
Как оно, блядь, работает:
Вот есть у тебя функция внутри функции. И эта внутренняя, мелкая, цепляется взглядом за какую-то переменную снаружи, не свою. И Python такой: «О, сука, привязка!» — и намертво пришивает эту переменную к внутренней функции. Прям в специальный карман, который __closure__ называется. И таскает она его с собой, пока не сдохнет.
Три пункта, чтобы эта магия случилась, ёпта:
- Функция внутри функции — это само собой, блядь. Без этого нихуя не выйдет.
- Внутренняя функция должна тыкать пальцем в переменную из внешней, типа «это моё!». Это называется «свободная переменная», хотя она уже не очень-то свободная, блядь.
- Внешняя функция должна выплюнуть эту внутреннюю наружу, как результат. Не просто вызвать, а именно отдать.
Смотри, как это выглядит вживую, блядь:
def outer_func(text):
# 'text' — вот она, свободная, как ветер. Пока что.
def inner_func():
# А вот inner_func уже на неё глаз положила. Замыкает, сука.
print(text)
return inner_func
# Вызываем внешнюю. Она отработала и сдохла, её 'text' должен был испариться.
# Но нет, блядь! Внутренняя функция его утащила с собой.
printer_hello = outer_func("Привет")
printer_world = outer_func("Мир")
# А теперь вызываем этих утырков. И они помнят!
printer_hello() # Вывод: Привет
printer_world() # Вывод: Мир
# Можно даже залезть в тот самый карман и посмотреть, что там спизжено.
print(printer_hello.__closure__[0].cell_contents) # Вывод: Привет
А где это, блядь, пригождается в жизни?
- Декораторы: Это вообще царство замыканий, ёпта. Без них нихуя бы не работало.
- Фабрики функций: Как в примере выше — штампуешь функции с разным предустановленным текстом, и каждая таскает свой.
- Хранение состояния без классов: Ну, типа, счётчик сделать, который помнит, сколько раз его дернули. Почти как объект, только проще, блядь. Для хитрожопых.