Замыкания (closure) в Python (ч.2) /21+

Замыкания с изменяемыми переменными

Использование nonlocal

Для изменения переменных из внешней области видимости используется ключевое слово nonlocal:

def create_bank_account(initial_balance=0):

    """Создает функцию для управления банковским счетом"""

    balance = initial_balance

        def account_manager(action, amount=0):

        nonlocal balance

        if action == "deposit":

            balance += amount

            return f"Пополнение на {amount}. Баланс: {balance}"

        elif action == "withdraw":

            if amount <= balance:

                balance -= amount

                return f"Снятие {amount}. Баланс: {balance}"

            else:

                return f"Недостаточно средств. Баланс: {balance}"

        elif action == "balance":

            return f"Текущий баланс: {balance}"

        else:

            return "Неизвестная операция"

    return account_manager

 

# Создаем счета

alice_account = create_bank_account(1000)

bob_account = create_bank_account(500)

 

# Операции со счетами

print(alice_account("balance"))

print(alice_account("deposit", 250))

print(alice_account("withdraw", 100))

print(alice_account("withdraw", 2000))

 

print("\n" + "="*30 + "\n")

print(bob_account("balance"))

print(bob_account("deposit", 100))

print(bob_account("withdraw", 300))

 

Замыкания с изменяемыми объектами

def create_shopping_cart():

    """Создает корзину покупок с использованием замыкания"""

    items = []

    def cart_manager(action, item=None, quantity=1):

        if action == "add":

            items.append({"name": item, "quantity": quantity})

            return f"Добавлен товар: {item} (количество: {quantity})"

        elif action == "remove":

            items[:] = [i for i in items if i["name"] != item]

            return f"Товар {item} удален из корзины"

        elif action == "list":

            if not items:

                return "Корзина пуста"

            return "Товары в корзине:\n" + "\n".join([f"- {i['name']}: {i['quantity']} шт." for i in items])

        elif action == "total":

            total_items = sum(item["quantity"] for item in items)

            return f"Общее количество товаров: {total_items}"

        elif action == "clear":

            items.clear()

            return "Корзина очищена"

    return cart_manager

 

# Использование корзины покупок

my_cart = create_shopping_cart()

print(my_cart("add", "яблоки", 5))

print(my_cart("add", "молоко", 2))

print(my_cart("add", "хлеб", 1))

print()

print(my_cart("list"))

print()

print(my_cart("total"))

print()

print(my_cart("remove", "молоко"))

print(my_cart("list"))

print()

print(my_cart("clear"))

print(my_cart("list"))

 

Замыкания в циклах

При работе с замыканиями в циклах важно понимать особенности их поведения:

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

# Неправильный подход

def create_functions_wrong():

    functions = []

    for i in range(3):

        def func():

            return i  # i будет ссылаться на последнее значение из цикла

        functions.append(func)

    return functions

 

# Все функции вернут 2 (последнее значение i)

wrong_functions = create_functions_wrong()

print("Неправильный подход:")

for func in wrong_functions:

    print(func())  # Вывод: 2, 2, 2

 

# Правильный подход с использованием параметра по умолчанию

def create_functions_correct():

    functions = []

    for i in range(3):

        def func(x=i):  # Захватываем текущее значение i

            return x

        functions.append(func)

    return functions

correct_functions = create_functions_correct()

print("\nПравильный подход:")

for func in correct_functions:

    print(func())  # Вывод: 0, 1, 2

 

# Альтернативный правильный подход с дополнительной функцией

def create_functions_alternative():

    functions = []

    def make_func(value):

        def func():

            return value

        return func

    for i in range(3):

        functions.append(make_func(i))

    return functions

 

alternative_functions = create_functions_alternative()

print("\nАльтернативный правильный подход:")

for func in alternative_functions:

    print(func())  # Вывод: 0, 1, 2

 

Производительность и память

Управление памятью в замыканиях

import sys

def analyze_closure_memory():

    """Анализ использования памяти замыканиями"""

    def outer_function(data):

        large_list = list(range(1000))  # Большой список

        small_var = data

        def inner_function():

            # Используем только small_var, но large_list тоже остается в памяти

            return small_var * 2

        return inner_function

   

    # Создаем замыкание

    closure = outer_function(42)

    # Проверяем, какие переменные захвачены

    print("Захваченные переменные:", closure.__code__.co_freevars)

    # Размер объекта замыкания

    print(f"Размер замыкания: {sys.getsizeof(closure)} байт")

    return closure

 

# Пример оптимизированного замыкания

def create_optimized_closure(data):

    """Оптимизированное замыкание, которое не захватывает лишние переменные"""

    def inner_function(captured_data=data):

        return captured_data * 2

    return inner_function

print("Анализ памяти:")

closure1 = analyze_closure_memory()

closure2 = create_optimized_closure(42)

print(f"\nРазмер обычного замыкания: {sys.getsizeof(closure1)} байт")

print(f"Размер оптимизированного замыкания: {sys.getsizeof(closure2)} байт")

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

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

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

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

Лого

Spartacus_85 [Admin]

Администратор сайта — это специалист, который отвечает за техническую поддержку и бесперебойную работу веб-ресурса.



0 Комментарий(я)

Зарегистрируйтесь чтобы оставить комментарий