⚖️ Старый и современный подход

⚡ Различия в двух словах

Старый: ручное открытие и закрытие соединения, код на верхнем уровне файла.

Новый: контекстный менеджер with гарантирует закрытие ресурсов, а if __name__ == "__main__": защищает код от случайного запуска при импорте.

Вывод: современный подход надёжнее и чище.

📜 Старый подход: ручное управление ресурсами

import pymysql

connection = pymysql.connect(host="localhost", user="root", password="secret", database="shop")
cursor = connection.cursor()
cursor.execute("SELECT * FROM products")
for row in cursor.fetchall():
    print(row)
cursor.close()
connection.close()

Что здесь происходит: код работает, но если между строками возникнет исключение, cursor.close() и connection.close() могут не выполниться. Это приводит к «утечке» открытых соединений.

❌ Почему ручной подход не лучший

  • Утечка ресурсов: при ошибке соединение может остаться открытым.
  • Дублирование: приходится везде писать cursor.close() и connection.close().
  • Код на верхнем уровне: при импорте модуля запросы выполняются немедленно, что неожиданно для пользователя модуля.

✅ Современный вариант: with и точка входа

import pymysql


def get_products():
    with pymysql.connect(
        host="localhost",
        user="root",
        password="secret",
        database="shop"
    ) as connection:
        with connection.cursor() as cursor:
            cursor.execute("SELECT * FROM products")
            return cursor.fetchall()


if __name__ == "__main__":
    for product in get_products():
        print(product)

Что улучшилось:

  • Контекстный менеджер with автоматически закрывает курсор и соединение, даже если произошла ошибка.
  • Логика работы с базой вынесена в функцию, которую легко протестировать и переиспользовать.
  • Блок if __name__ == "__main__": гарантирует, что демонстрационный код запустится только при прямом запуске файла.

✅ Современный вариант для MongoDB

from pymongo import MongoClient


def update_prices(collection):
    collection.delete_many({})
    collection.insert_many([
        {"name": "Pen", "price": 1.50},
        {"name": "Notebook", "price": 3.99},
    ])
    result = collection.update_many({}, {"$mul": {"price": 1.2}})
    return result.modified_count


if __name__ == "__main__":
    with MongoClient("mongodb://localhost:27017") as client:
        db = client["ich_edit"]
        collection = db["products_pd_ivanov"]
        count = update_prices(collection)
        print(f"Updated {count} products")

Что улучшилось: MongoClient тоже поддерживает контекстный менеджер и сам закроет пул соединений при выходе из блока with.

🕰️ Когда старый подход ещё можно встретить

В старых учебниках и legacy-проектах вы можете увидеть ручные вызовы close(). Если попадается такой код, проверяйте:

  • Есть ли гарантия закрытия ресурсов при исключении?
  • Не выполняется ли код на уровне модуля при импорте?

При рефакторинге лучше переписать такие участки на with и выделить точку входа if __name__ == "__main__":.