2013-04-11 2 views
5

Так было много ненависти к синглонам на питоне. Обычно я вижу, что наличие синглета - это , обычно ничего хорошего, но как насчет того, что имеет побочные эффекты, например, используя/запрашивая базу данных? Почему я должен создать новый экземпляр для каждого простого запроса, когда я снова смогу повторно использовать существующее соединение? Какой был бы питонический подход/альтернатива этому?DB-Connections Класс как Singleton в Python

Спасибо!

ответ

6

Обычно у вас есть объект, представляющий объект, который использует базу данных (например, экземпляр MyWebServer), и вы делаете соединение с базой данных членом этого объекта.

Если у вас есть вся ваша логика внутри какой-либо функции, сделайте соединение локальным для этой функции. (Это не слишком распространено на многих других языках, но в Python часто есть хорошие способы обернуть многоступенчатую работу с состоянием в одной функции генератора.)

Если у вас есть все базы данных, над местом, то просто используйте глобальную переменную вместо синглтона. Да, глобалы плохие, но одиночные игры так же плохи и сложнее. Есть несколько случаев, когда они полезны, но очень редки. (Это не обязательно верно для других языков, но это для Python.) И способ избавиться от глобального - это переосмыслить дизайн. Там хороший шанс, что вы эффективно использовать модуль в качестве (Singleton) объекта, и если вы думаете, через это, вероятно, можно придумать хороший класс или функцию, чтобы обернуть его в.


Очевидно просто перемещая все ваши глобальные переменные в атрибуты класса, а @classmethod s просто дает вам глобальные переменные под другим пространством имен. Но переместить их в экземпляр атрибуты и методы - это совсем другая история. Это дает вам объект, который вы можете пройти, и, при необходимости, объект, в котором вы можете иметь 2 (или, возможно, даже 0 при некоторых обстоятельствах), присоединить блокировку, сериализацию и т. Д.

Во многих типах приложений , вы все равно получите один экземпляр чего-то - каждое приложение Qt GUI имеет ровно один MyQApplication, почти каждый веб-сервер имеет ровно один MyWebServer и т. д. Независимо от того, что вы называете это, это эффективно одноэлементный или глобальный. И если вы хотите, вы можете просто переместить все в атрибуты этого объекта божества.

Но только потому, что вы может это не значит, что вы должны. У вас все еще есть параметры функции, локальные переменные, глобальные переменные в каждом модуле, другие (немигалитические) классы с их собственными атрибутами экземпляра и т. Д., И вы должны использовать все, что подходит для каждого значения.

Например, ваш MyWebServer создает новый экземпляр ClientConnection для каждого нового клиента, который подключается к вам. Вы могли бы сделать соединения писать MyWebServer.instance.db.execute всякий раз, когда они хотят выполнить SQL-запрос ... но вы также можете просто передать self.db в конструктор ClientConnection, и каждое соединение затем просто выполняет self.db.execute. Итак, какой из них лучше? Ну, если вы это сделаете последним, это упростит ваш код и рефакторинг. Если вы хотите загрузить баланс в 4 базах данных, вам нужно всего лишь изменить код в одном месте (где MyWebServer инициализирует каждый ClientConnection) вместо 100 (каждый раз, когда ClientConnection обращается к базе данных). Если вы хотите конвертировать свое монолитное веб-приложение в контейнер WSGI, вам не нужно менять какой-либо код ClientConnection, за исключением, может быть, конструктора. И так далее.

+0

вид приложение = class.webapp(); app.dbconn = class.dbconn()? Действительно ли это все, что отличается от синглтона в конце? – AlessandroEmm

+0

@AlessandroMeyer: Позвольте мне отредактировать ответ на адрес. – abarnert

1

Если вы используете объектно-ориентированный подход, то предложение abamet о присоединении параметров подключения к базе данных как атрибутов класса имеет смысл для меня. Затем класс может установить одно соединение с базой данных, которое, например, относится ко всем методам класса, например, self.db_connection.

Если вы не используете объектно-ориентированный подход, отдельный модуль подключения базы данных может обеспечить эквивалент функционального стиля. Предоставьте модуль для установления соединения с базой данных и просто импортируйте этот модуль везде, где вы хотите его использовать. Например, ваш код может ссылаться на соединение как db.connection. Поскольку модули являются эффективными синглтонами, а код модуля запускается только при первом входе , вы будете повторно использовать одно и то же соединение с базой данных каждый раз.

+0

@JeffryFroman. Моя проблема с использованием модуля заключается в том, что мне нравится идея иметь глобальное, но все еще одноэлементное внутреннее состояние. – AlessandroEmm

+0

Как вы, например, решить «сохранение» параметров подключения БД? Просто иметь их в одних и тех же модулях было бы немного беспорядочно, а их в общем модуле, подобном модулю, сделало бы модуль базы данных строго зависимым от этого. – AlessandroEmm

Смежные вопросы