Являются ли синглтоны «плохими» или нет, похоже, являются предметом вкуса. Конечно, у них есть свое место, и любой из вариантов одной темы должен работать на вас.
«Borg узор» (менее красочно & гораздо реже, «StatelessProxy» или «Monostate») была популярной альтернативой Python для Singleton вероятно с тех пор умный рецепт ActiveState Алекс Мартелли в Singleton? We don't need no stinkin' singleton: the Borg design pattern. Он отличается от Singleton тем, что позволяет создавать несколько отдельных объектов класса, все используют общие данные. Образец Singleton, напротив, гарантирует, что только один экземпляр класса будет создан.
Обсуждение Borg vs Вопрос о Singleton можно найти в этом сообщении stackoverflow: Why is the Borg pattern better than the Singleton pattern in Python. Реализации в верхней части сообщения могут быть недоумением из-за отсутствующего метода _init_default_register
, целью которого является создание и инициализация общих атрибутов данных только один раз. Для справки и сравнения здесь приведены полные реализации (в Python 3), оба из которых создают единый атрибут данных (dict с именем data
):
Стандартный способ реализации Singleton в Python - это метакласс;
class Singleton(type):
def __init__(cls, *args, **kwargs):
cls.__instance = None
super().__init__(*args, **kwargs)
def __call__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super().__call__(*args, **kwargs)
return cls.__instance
Вы бы сделать свой класс статистики слежения одноэлементно, придав ему это метакласса:
class StatsTrackerSingleton(metaclass=Singleton):
def __init__(self):
self.data = {}
# ... methods to update data, summarize it, etc. ...
Узор Борг проще в реализации, и, поскольку он не использует метакласса, потенциально более гибкий:
class StatsTrackerBorg():
__shared_data = {'data':{}}
# RHS guarantees a common dict named `data`
def __init__(self):
"""Make every instance use StatsTrackerBorg.__shared_data
for its attribute dict."""
self.__dict__ = self.__shared_data
# ... methods to update data, summarize it, etc. ...
с обеих моделей, как это реализовано выше, вы можете использовать общий Dict data
, и вы можете просто получить и установить общие атрибуты, используя Д.О. t. Например, с помощью класса Borg:
>>> a = StatsTrackerBorg()
>>> b = StatsTrackerBorg()
>>> a is b # would be True for StatsTrackerSingleton
False
>>> vars(a) is vars(b)
True
>>> vars(a)
{'data': {}}
>>> a.data['running_time'] = 10000
>>> b.bar = 10
>>> vars(a)
{'data': {'running_time': 10000}, 'bar': 10}
>>> b.foo = 'y'
>>> a.foo
'y'
Заметной разница между двумя фигурами: подкласс классом акций «Borg'ed» то же общим состоянием с суперклассом, и все еще может добавить более общее состояние доступно к его экземплярам, тогда как каждый подкласс класса Singleton получает свой собственный уникальный экземпляр и, следовательно, его собственное общее состояние, не связанное с классом суперкласса. Для некоторых предполагаемых приложений одно из этих действий может быть явно более подходящим, чем другое.
Почему бы просто не использовать словарь? – Alexander