Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Python

Замыкания в Python: как вложенные функции захватывают переменные

Замыкания в Python

Узнайте, как работают замыкания в Python, как их определять и почему они необходимы для чистого, эффективного кода.

Переменные nonlocal во вложенной функции

Прежде чем изучать замыкания, важно понять вложенные функции и nonlocal-переменные. Функция, определённая внутри другой функции, называется вложенной. Такие функции могут читать переменные из объемлющей области видимости.

В Python эти nonlocal-переменные доступны только для чтения по умолчанию. Чтобы изменить их, нужно явно объявить переменную как nonlocal внутри вложенной функции.

Ниже — простой пример, показывающий вложенную функцию, обращающуюся к nonlocal-переменной.

def print_msg(msg):
    # Внешняя функция
    def printer():
        # Вложенная функция
        print(msg)
    printer()  # Выполнение
print_msg("Hello")

Вывод

Hello

Вложенная функция printer() может получить доступ к переменной msg из своей внешней области видимости.


Определение функции-замыкания

Что, если внешняя функция вернёт вложенную функцию вместо её вызова? Код выглядел бы так:

def print_msg(msg):
    def printer():
        print(msg)
    return printer  # Возврат вложенной функции
# Сохранение возвращённой функции
another = print_msg("Hello")
another()

Вывод

Hello

Обратите внимание: функция printer всё ещё помнит значение msg даже после завершения print_msg. Это явление — когда функция сохраняет доступ к переменным из своей области определения — называется замыканием в Python.

Для наглядности удалим исходную функцию и увидим, что возвращённая всё ещё работает:

>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined

Возвращённая функция продолжает работать, потому что она захватила необходимые данные в своём замыкании.


Когда возникают замыкания?

В Python замыкание существует, когда вложенная функция:


Когда использовать замыкания?

Замыкания предлагают несколько преимуществ:

Ниже — распространённый пример: фабрика, создающая функции-умножители.

def make_multiplier_of(n):
    def multiplier(x):
        return x * n
    return multiplier
# Создание конкретных умножителей
times3 = make_multiplier_of(3)
times5 = make_multiplier_of(5)
print(times3(9))  # 27
print(times5(3))  # 15
print(times5(times3(2)))  # 30

Вывод

27
15
30

Синтаксис декораторов Python сильно опирается на замыкания. Когда вы пишете декоратор, обёртка захватывает декорируемую функцию, образуя замыкание.

Для инспекции замыкания используйте атрибут __closure__. Он возвращает кортеж cell-объектов, содержащих захваченные значения. Например:

>>> 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-код, избегая лишних глобальных переменных и принимая функциональные парадигмы.

Python

  1. Освоение типов данных в Python: практическое руководство
  2. Мастерство операторов Python: Полное руководство
  3. Оператор pass в Python: практическое руководство
  4. Lambda-функции в Python: практическое руководство по анонимным функциям
  5. Словари в Python: создание, манипуляции и продвинутые техники
  6. Генераторы в Python: эффективная итерация и продвинутые сценарии
  7. Декораторы в Python: улучшайте функции экспертными техниками
  8. Мастерство метода strip() в Python: подробное руководство и практические примеры
  9. Освоение лямбда-функций Python: практические примеры и лучшие практики
  10. Функция abs() в Python: вычисление абсолютных значений для чисел и комплексных чисел