Синглтон Оформитель


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

class Singleton:
    """
    Helper class meant to ease the creation of singletons. This
    should be used as a decorator -- not a metaclass -- to the class
    that should be a singleton.

    The decorated class should define only one `__init__` function
    that takes only the `self` argument. Other than that, there are
    no restrictions that apply to the decorated class.

    To get the singleton instance, use the `Instance` method. Trying
    to use `__call__` will result in a `SingletonError` being raised.

    """

    _singletons = dict()

    def __init__(self, decorated):
        self._decorated = decorated

    def Instance(self):
        """
        Returns the singleton instance. Upon its first call, it creates a
        new instance of the decorated class and calls its `__init__` method.
        On all subsequent calls, the already created instance is returned.

        """
        key = self._decorated.__name__

        try:
            return Singleton._singletons[key]
        except KeyError:
            Singleton._singletons[key] = self._decorated()
            return Singleton._singletons[key]

    def __call__(self):
        """
        Call method that raises an exception in order to prevent creation
        of multiple instances of the singleton. The `Instance` method should
        be used instead.

        """
        raise SingletonError(
            'Singletons must be accessed through the `Instance` method.')


class SingletonError(Exception):
    pass

Сейчас, чтобы проверить, если в документации было достаточно ясно думать о том, как вы поняли, этот класс предназначен для использования в... теперь посмотрим на этот пример и сравнить:

@Singleton
class Foo:
    def __init__(self):
        print('Foo created')

    def bar(self, obj):
        print(obj)

foo = Foo()  # Wrong, raises SingletonError

foo = Foo.Instance() # Good; prints 'Foo created' 
goo = Foo.Instance() # Already created, prints nothing

print(goo is foo) # True

foo.bar('Hello, world! I\'m a singleton.')


3396
4
задан 7 сентября 2011 в 04:09 Источник Поделиться
Комментарии
4 ответа

Это может быть полезно добавить позиционные и именованные параметры в типа__Call__() метод. Таким образом, вы получите ваш SingletonError для любого звонка вы пытаетесь сделать, а не просто без аргументов вызова.

Вы можете добавить методы, чтобы удалить или переопределить синглтоны, если это необходимо или перестроить свой класс для решения конфликтов имен. Он сломается, если вы определить одно Singleton и использовать его, а затем переопределить новый Singleton, используя то же имя.

Рассмотреть вопрос о внесении экземпляра свойство, а не метод.

Рассмотреть вопрос об использовании "нового стиля" явно синтаксис класс.

3
ответ дан 7 сентября 2011 в 08:09 Источник Поделиться

Хммм, если это вызывается из нескольких потоков, то он может создать несколько экземпляров. Итак, какой замок будет приветствоваться.

2
ответ дан 7 сентября 2011 в 04:09 Источник Поделиться


  1. Вы можете положить ваш пример как doctest, или вам необходимо написать небольшое unittest

  2. Что делать, если ФОО нужны параметры?

2
ответ дан 7 сентября 2011 в 07:09 Источник Поделиться

Синглтоны-зло, не используйте их. Синглтоны-это просто усложненная версия глобальной переменной. Ваш лучший вариант это вообще отказаться от глобальных переменных, а не изобретать их. См http://www.youtube.com/watch?v=-FRm3VPhseI для обсуждения вопроса о том, как реально избежать глобальных переменных.

Почему вы храните элементы в качестве словаря на объект класса, а затем в качестве атрибута на локальный объект?

Руководство по стилю Python говорит, что методы должны быть lowercase_with_underscores.

В __звоните__ переопределение сомнительно полезным. Может быть, просто давая по умолчанию в Python нет __звоните__ определенными будет достаточно. Это не нравится кому-то ловить SingletonError

Редактировать

Применении пункта 2, нет необходимости для класса-уровня предсказывает.

class Singleton:
def __init__(self, decorated):
self._decorated = decorated
self._value = None

def Instance(self):
if self._value is None:
self._value = self._decorated()

return self._value

1
ответ дан 7 сентября 2011 в 09:09 Источник Поделиться