Python синглтон / создание объекта - PullRequest
6 голосов
/ 01 сентября 2009

Я изучаю Python и пытаюсь реализовать класс типа Singleton в качестве теста. У меня есть следующий код:

_Singleton__instance = None

class Singleton:
    def __init__(self):
        global __instance
        if __instance == None:           
            self.name = "The one"
            __instance = self
        else:
            self = __instance

Это работает частично, но кажется, что часть self = __instance не работает. Я включил некоторые выходные данные интерпретатора для демонстрации (код выше сохранен в singleton.py):

>>> import singleton
>>> x = singleton.Singleton()
>>> x.name
'The one'
>>> singleton._Singleton__instance.name
'The one'
>>> y = singleton.Singleton()
>>> y.name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Singleton instance has no attribute 'name'
>>> type(y)
<type 'instance'>
>>> dir(y)
['__doc__', '__init__', '__module__']

Можно ли сделать то, что я пытаюсь? Если нет, есть ли другой способ сделать это?

Любые предложения приветствуются.

Приветствие.

Ответы [ 5 ]

22 голосов
/ 01 сентября 2009

Присвоение аргументу или любой другой локальной переменной (голое имя) никогда не может, возможно, иметь ЛЮБОЙ эффект вне функции; это относится к вашему self = whatever, как к ЛЮБОМУ другому назначению аргумента (barename) или другой локальной переменной.

Скорее, переопределить __new__:

class Singleton(object):

    __instance = None

    def __new__(cls):
        if cls.__instance == None:
            cls.__instance = object.__new__(cls)
            cls.__instance.name = "The one"
        return cls.__instance

Я сделал здесь другие улучшения, такие как выкорчевывание глобального, класс старого стиля и т. Д.

Гораздо лучше использовать Borg (он же monostate) вместо выбранного вами Highlander (он же синглтон), но это не та проблема, о которой вы спрашиваете; -).

6 голосов
/ 01 сентября 2009

Фрагмент кода Брюса Экеля из Design Pattern: я не понимаю, как это работает

class Borg:
  _shared_state = {}
  def __init__(self):
    self.__dict__ = self._shared_state

class MySingleton(Borg):
  def __init__(self, arg):
    Borg.__init__(self)
    self.val = arg
  def __str__(self): return self.val

x = MySingleton('sausage')
print x
y = MySingleton('eggs')
print y
z = MySingleton('spam')
print z
print x
print y
print ´x´
print ´y´
print ´z´
output = '''
sausage
eggs
spam
spam
spam
<__main__. MySingleton instance at 0079EF2C>
<__main__. MySingleton instance at 0079E10C>
<__main__. MySingleton instance at 00798F9C>
'''
4 голосов
/ 01 сентября 2009

От Шаблон Singleton (Python) :

class Singleton(type):
    def __init__(self, name, bases, dict):
        super(Singleton, self).__init__(name, bases, dict)
        self.instance = None

    def __call__(self, *args, **kw):
        if self.instance is None:
            self.instance = super(Singleton, self).__call__(*args, **kw)

        return self.instance

class MyClass(object):
    __metaclass__ = Singleton

print MyClass()
print MyClass()
3 голосов
/ 01 сентября 2009

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

class Singleton:
    instance = None

    @classmethod
    def get(cls):
        if cls.instance is None:
            cls.instance = cls()
        return cls.instance

    def __init__(self):
        self.x = 5       # or whatever you want to do

sing = Singleton.get()
print sing.x  # prints 5

Что касается того, почему ваш код не работает, есть несколько причин. Во-первых, к тому времени, когда вызывается __init__, новый объект уже создан, побеждая назначение шаблона синглтона. Во-вторых, когда вы говорите self = __instance, это просто сбрасывает локальную переменную self; это было бы похоже на высказывание

def f(x):
  x = 7    # changes the value of our local variable

y = 5
f(y)
print y   # this is still 5

Поскольку переменные в Python передаются по значению, а не по ссылке, вы не можете сказать self = blah, и он будет иметь смысл так, как вы хотите. Вышеприведенный класс Singleton - это больше, чем вы хотите, если только вы не хотите придумать и изучить переопределение оператора __new__.

0 голосов
/ 01 сентября 2009
self = _instance

Это не будет делать то, что вы ожидаете. Читайте о том, как Python обрабатывает имена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...