class DatabaseConnection:
    def __init__(self, host, database):
     self.host = host
     self.database = database
     self.connection = None
    def __enter__(self):
     self.connection = self.connect() # Реальная логика подключения
     return self.connection
    def __exit__(self, exc_type, exc_val, exc_tb):
     if self.connection:
      self.connection.close()  # Реальная логика закрытия соединения
   with DatabaseConnection("localhost", "mydb") as db:
    # Работа с соединением (db)
    cursor = db.cursor()
    cursor.execute("SELECT * FROM users")
    result = cursor.fetchall()
    # ...
   # Соединение автоматически закрывается после выхода из блока with
  __enter__ устанавливается соединение, а в __exit__ гарантированно закрывается, даже если возникнет ошибка внутри блока with.  exc_type, exc_val и exc_tb содержат информацию об исключении, если оно произошло.
 Контекстные менеджеры в Python – это мощный инструмент для управления ресурсами, гарантирующий их корректное освобождение после использования, даже при возникновении исключений. Для сетевых соединений и баз данных они особенно полезны, поскольку позволяют автоматически закрывать соединения, освобождать ресурсы и обрабатывать транзакции.
Работа с сетевыми соединениями (например, через socket):
Хотя напрямую socket не предоставляет готовый контекстный менеджер, его можно легко создать с помощью библиотеки contextlib и декоратора contextmanager:
import socket
from contextlib import contextmanager
@contextmanager
def socket_connection(host, port):
    """Контекстный менеджер для работы с сокетом."""
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect((host, port))
        yield sock
    finally:
        sock.close()
# Пример использования:
with socket_connection('example.com', 80) as s:
    s.sendall(b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n")
    response = s.recv(4096)
    print(response.decode())
    # Сокет автоматически закрывается после выхода из блока 'with'
    В этом примере:
@contextmanager превращает функцию socket_connection в контекстный менеджер.yield sock возвращает объект сокета, который используется внутри блока with.finally гарантируется закрытие сокета, даже если в блоке with возникнет исключение.Работа с базами данных (например, с sqlite3):
Многие библиотеки для работы с базами данных, включая sqlite3, предоставляют встроенные контекстные менеджеры:
import sqlite3
db_path = 'mydatabase.db'
with sqlite3.connect(db_path) as conn:
    cursor = conn.cursor()
    cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")
    cursor.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)")
    cursor.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)")
    conn.commit()  # Подтверждаем изменения
    for row in cursor.execute("SELECT * FROM users"):
        print(row)
    # Соединение автоматически закрывается и транзакция коммитится (или откатывается при исключении)
    В этом примере:
sqlite3.connect() возвращает объект соединения, который действует как контекстный менеджер.with устанавливается соединение с базой данных.conn.commit() явно подтверждает транзакцию. Если произойдет исключение до вызова conn.commit(), транзакция будет автоматически отменена при выходе из блока with.  Если conn.commit() вызван, изменения фиксируются, и соединение закрывается при выходе из блока.with соединение автоматически закрывается, и, если не было вызвано исключение, транзакция подтверждается. В противном случае транзакция откатывается.Преимущества использования контекстных менеджеров:
Таким образом, контекстные менеджеры – это ценный инструмент для написания надежного и эффективного кода при работе с сетевыми соединениями и базами данных в Python.