Этот вопрос не для обсуждения того, желателен ли шаблон проектирования Singleton, является ли он антишаблоном или для каких-либо религиозных войн, а для обсуждения того, как этот шаблон лучше всего реализовать в Python в таком это самый питонический способ. В данном случае я определяю термин «самый питонический» как означающий, что он следует «принципу наименьшего удивления»..
У меня есть несколько классов, которые станут одиночными (мой вариант использования это для логгера, но это не важно). Я не хочу загромождать несколько классов добавлением глупостей, когда я могу просто наследовать или дополнять их.
Лучшие методы:
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
@singleton
class MyClass(BaseClass):
pass
Плюсы
Декораторы аддитивны, что зачастую более интуитивно понятно, чем множественное наследование.
Минусы
Хотя объекты, созданные с помощью MyClass(), будут истинными одиночные объекты, MyClass сам по себе является функцией, а не классом, поэтому вы не можете вызывать из него методы класса. Также для
class Singleton(object):
_instance = None
def __new__(class_, *args, **kwargs):
if not isinstance(class_._instance, class_):
class_._instance = object.__new__(class_, *args, **kwargs)
return class_._instance
class MyClass(Singleton, BaseClass):
pass
Плюсы
Это настоящий класс
Минусы
Множественное наследование — фу! __new__ может быть перезаписан во время наследования от второго базового класса? Приходится думать больше, чем необходимо.
def singleton(class_):
class class_w(class_):
_instance = None
def __new__(class_, *args, **kwargs):
if class_w._instance is None:
class_w._instance = super(class_w,
class_).__new__(class_,
*args,
**kwargs)
class_w._instance._sealed = False
return class_w._instance
def __init__(self, *args, **kwargs):
if self._sealed:
return
super(class_w, self).__init__(*args, **kwargs)
self._sealed = True
class_w.__name__ = class_.__name__
return class_w
@singleton
class MyClass(BaseClass):
pass
Плюсы
Это настоящий класс
Автоматически волшебным образом охватывает наследование
Минусы
Нет ли накладных расходов на создание каждого нового класса? Здесь мы создаем два класса для каждого класса, который хотим сделать синглтоном. Хотя в моем случае это нормально, я беспокоюсь, что это может не масштабироваться. Конечно, есть споры о том, не слишком ли легко масштабировать этот шаблон...
В чем смысл атрибута _sealed
Невозможно вызвать методы с тем же именем в базовых классах с помощью super(), поскольку они будут рекурсивными. Это означает, что вы не можете настраивать __new__ и не можете создавать подклассы для класса, который требует вызова __init__.
Этот вопрос не для обсуждения того, желателен ли шаблон проектирования Singleton, является ли он антишаблоном или для каких-либо религиозных войн, а для обсуждения того, как этот шаблон лучше всего реализовать в Python в таком это самый питонический способ. В данном случае я определяю термин «самый питонический» как означающий, что он следует «принципу наименьшего удивления».. У меня есть несколько классов, которые станут одиночными (мой вариант использования это для логгера, но это не важно). Я не хочу загромождать несколько классов добавлением глупостей, когда я могу просто наследовать или дополнять их. Лучшие методы:
< h2>Метод 1: Декоратор [code]def singleton(class_): instances = {} def getinstance(*args, **kwargs): if class_ not in instances: instances[class_] = class_(*args, **kwargs) return instances[class_] return getinstance
@singleton class MyClass(BaseClass): pass [/code] Плюсы [list] [*]Декораторы аддитивны, что зачастую более интуитивно понятно, чем множественное наследование.[/list] Минусы [list] [*]Хотя объекты, созданные с помощью MyClass(), будут истинными одиночные объекты, MyClass сам по себе является функцией, а не классом, поэтому вы не можете вызывать из него методы класса. Также для [code]x = MyClass(); y = MyClass(); t = type(n)(); [/code]
[/list] тогда x == y, но x != t && y != t
Метод 2: базовый класс [code]class Singleton(object): _instance = None def __new__(class_, *args, **kwargs): if not isinstance(class_._instance, class_): class_._instance = object.__new__(class_, *args, **kwargs) return class_._instance
class MyClass(Singleton, BaseClass): pass [/code] Плюсы [list] [*]Это настоящий класс [/list] Минусы [list] [*]Множественное наследование — фу! __new__ может быть перезаписан во время наследования от второго базового класса? Приходится думать больше, чем необходимо. [/list]
Метод 3: Метакласс [code]class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls]
#Python2 class MyClass(BaseClass): __metaclass__ = Singleton
#Python3 class MyClass(BaseClass, metaclass=Singleton): pass [/code] Плюсы [list] [*]Это настоящий класс [*]Автоматически волшебным образом охватывает наследование [*]Использует __metaclass__ по прямому назначению (и сообщил мне об этом) [/list] Минусы< /p> [list] [*]Есть ли они? [/list]
Метод 4 : декоратор возвращает класс с тем же именем [code]def singleton(class_): class class_w(class_): _instance = None def __new__(class_, *args, **kwargs): if class_w._instance is None: class_w._instance = super(class_w, class_).__new__(class_, *args, **kwargs) class_w._instance._sealed = False return class_w._instance def __init__(self, *args, **kwargs): if self._sealed: return super(class_w, self).__init__(*args, **kwargs) self._sealed = True class_w.__name__ = class_.__name__ return class_w
@singleton class MyClass(BaseClass): pass [/code] Плюсы [list] [*]Это настоящий класс [*]Автоматически волшебным образом охватывает наследование [/list] Минусы [list] [*]Нет ли накладных расходов на создание каждого нового класса? Здесь мы создаем два класса для каждого класса, который хотим сделать синглтоном. Хотя в моем случае это нормально, я беспокоюсь, что это может не масштабироваться. Конечно, есть споры о том, не слишком ли легко масштабировать этот шаблон... [*]В чем смысл атрибута _sealed Невозможно вызвать методы с тем же именем в базовых классах с помощью super(), поскольку они будут рекурсивными. Это означает, что вы не можете настраивать __new__ и не можете создавать подклассы для класса, который требует вызова __init__. [/list]
Метод 5: модуль файл модуля singleton.py Плюсы [list] [*]Простое лучше сложного [/list] Минусы [list] [*]Не лениво создавать экземпляры [/list]
Этот вопрос не для обсуждения того, желателен ли шаблон проектирования Singleton, является ли он антипаттерном или для каких-либо религиозных войн, а для обсуждения того, как этот шаблон лучше всего реализовать в Python в таком это самый...
Этот вопрос не для обсуждения того, желателен ли шаблон проектирования Singleton, является ли он антипаттерном или для каких-либо религиозных войн, а для обсуждения того, как этот шаблон лучше всего реализовать в Python в таком это самый...
Этот вопрос не для обсуждения того, желателен ли шаблон проектирования Singleton, является ли он антипаттерном или для каких-либо религиозных войн, а для обсуждения того, как этот шаблон лучше всего реализовать в Python в таком это самый...
Этот вопрос не для обсуждения того, желателен ли шаблон проектирования Singleton, является ли он антипаттерном или для каких-либо религиозных войн, а для обсуждения того, как этот шаблон лучше всего реализовать в Python в таком это самый...