class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]
class Singleton(metaclass=SingletonMeta):
def some_business_logic(self):
...
Вызываем ли мы SingletonMeta()
?
Нет.
Автор присваивает s1 = Singleton()
, и аналогично s2
.
Это совсем другое.
Паттерн синглтона был абстрагирован,
поэтому он едва появляется в классе с бизнес-логикой.
Достаточно лишь краткого упоминания metaclass=SingletonMeta
, чтобы втянуть его.
Почему необходим dict
контейнер?
Потому что метакласс поддерживает несколько дочерних классов.
Вот несколько примеров, которые автор не предложил.
class WaffleSingleton(metaclass=SingletonMeta):
def make_waffles(self):
...
class PancakeSingleton(metaclass=SingletonMeta):
def make_pancakes(self):
...
В любом случае, на данный момент дикт метакласса будет содержать три записи.
Обратите внимание, что каждый из этих классов может быть размещен в отдельном модуле,
но общий импорт SingletonMeta
организует
для них обновление одного и того же dict
.
Упомянутый вами подход вполне осуществим. Это просто больше copy-n-paste boilerplate в каждом классе, который смотрит вам в лицо. Цель the metaclass approach была в том, чтобы быть минимально навязчивым, чтобы инженеры могли сосредоточиться на бизнес-логике.
Рекомендую посмотреть эти видео для лучшего погружения в вопрос: