0Pricing
Python Academy · Урок

Замыкания и свободные переменные

Сохраняйте состояние во вложенных функциях

«Замыкания и свободные переменные» — бесплатный урок Python Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Python Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Python Academy содержит 4 уроков всего.

Вложенные функции

В Python можно определить функцию внутри другой функции. Внутренняя функция создаётся заново при каждом запуске внешней функции.

def outer():
    def inner():
        return 'from inner'
    return inner()
print(outer())

Внутренняя функция видит переменные внешней

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

def outer():
    message = 'hello'
    def inner():
        return message
    return inner()
print(outer())

Что такое замыкание

Замыкание возникает, когда внутренняя функция возвращается и продолжает помнить свободные переменные из внешней области видимости даже после завершения этой области.

def make_greeter(name):
    def greet():
        return 'Hi ' + name
    return greet
g = make_greeter('Ada')
print(g())

Захваченное состояние сохраняется

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

def make_greeter(name):
    def greet():
        return 'Hi ' + name
    return greet
a = make_greeter('Ada')
b = make_greeter('Bob')
print(a())
print(b())

Фабрика multiplier

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

def multiplier(factor):
    def multiply(n):
        return n * factor
    return multiply
double = multiplier(2)
triple = multiplier(3)
print(double(10))
print(triple(10))

Каждое замыкание независимо

Каждый вызов фабрики создаёт отдельное замыкание со своим захваченным значением. Они не влияют друг на друга.

def adder(amount):
    def add(n):
        return n + amount
    return add
add5 = adder(5)
add100 = adder(100)
print(add5(1), add100(1))

Проверка захваченных значений

Захваченные имена перечислены в __code__.co_freevars, а их значения хранятся в ячейках __closure__.

def make(x):
    def f():
        return x
    return f
fn = make(42)
print(fn.__code__.co_freevars)
print(fn.__closure__[0].cell_contents)

Замыкания захватывают переменные, а не значения

Замыкание захватывает саму переменную, поэтому видит её конечное значение. Это важно, когда переменная изменяется после создания замыкания.

def build():
    x = 1
    def show():
        return x
    x = 99
    return show
print(build()())

Ловушка позднего связывания в цикле

Классическая неожиданность: все замыкания, созданные в цикле, используют одну и ту же переменную цикла, поэтому захватывают её последнее значение.

funcs = []
for i in range(3):
    funcs.append(lambda: i)
print([f() for f in funcs])

Исправление позднего связывания

Свяжите текущее значение с аргументом по умолчанию, чтобы каждое замыкание захватило собственную копию во время определения.

funcs = []
for i in range(3):
    funcs.append(lambda i=i: i)
print([f() for f in funcs])

Замыкания как лёгкие объекты

Замыкание объединяет данные и поведение, подобно небольшому объекту, и зачастую оказывается удобнее полноценного класса в простых случаях.

def counter_start(start):
    def value():
        return start
    return value
c = counter_start(10)
print(c())

Быстрая проверка

Что такое замыкание в Python?

Повторение: замыкания и свободные переменные

Основные идеи:

  • Внутренние функции могут читать переменные из внешней области видимости (свободные переменные).
  • Замыкание — это возвращённая внутренняя функция, которая помнит эти переменные.
  • Каждый вызов фабрики создаёт независимое замыкание.
  • Замыкания захватывают переменные, а не значения, что приводит к ловушке позднего связывания в цикле. Исправить её можно аргументом по умолчанию.
def power_of(exp):
    return lambda base: base ** exp
square = power_of(2)
print(square(9))

Часто задаваемые вопросы

Урок «Замыкания и свободные переменные» бесплатный?

Да — полный текст урока «Замыкания и свободные переменные» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Python Academy, подпишись на CoddyKit PRO. Курс Python Academy содержит 4 уроков всего.

Чему я научусь в уроке «Замыкания и свободные переменные»?

Сохраняйте состояние во вложенных функциях Ты практикуешь Python Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Python Academy?

Предыдущий опыт не требуется. Python Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Замыкания и свободные переменные»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Python Academy?

Да. Каждый урок Python Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Функции первого класса
  2. Замыкания и свободные переменные
  3. nonlocal и изменяемое состояние
  4. Частичные функции
← Назад к Python Academy