Ваш декоратор, кажется, работает нормально для меня, поскольку создает один экземпляр класса, поэтому я не вижу вашей проблемы # 1.Он работает не совсем так, как вы думаете: каждый раз, когда вы используете декоратор, появляется новый словарь instances
, и в нем всегда есть только один элемент, поэтому на самом деле нет никакой причины использовать там словарь - вам нужноизменяемый контейнер, так что вы можете изменить его, но я бы использовал список, или, в Python 3, возможно переменную nonlocal
.Тем не менее, он выполняет свою намеченную функцию, чтобы убедиться, что есть только один экземпляр декорированного класса.
Если вы спрашиваете, почему вы не можете создать новый экземпляр объекта после его закрытия, хорошо, выя не написал никакого кода, который позволял бы создавать другой экземпляр в этой ситуации, и Python не способен угадать, что вы хотите, чтобы это произошло.Синглтон означает, что существует только один экземпляр класса.Вы создали этот экземпляр;вы не можете создать другое.
Что касается # 2, ваш декоратор @singleton
возвращает функцию, которая создает (или возвращает ранее созданный экземпляр) класса.Поэтому Fire
- это функция, а не класс, когда-то оформленный, поэтому ваш isinstance()
не работает.
Самый простой подход к синглетам, на мой взгляд, состоит в том, чтобы поместитькласс, а не в декораторе, а затем наследовать от этого класса.Это даже имеет смысл с точки зрения наследования, поскольку синглтон является своего рода объектом.
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
class Fire(Singleton):
pass
f1 = Fire()
f2 = Fire()
f1 is f2 # True
isinstance(f1, Fire) # True
Если вы все еще хотите сделать это с помощью декоратора, самый простой подход заключается в создании промежуточногокласс в декораторе и вернуть это:
def singleton(D):
class C(D):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = D.__new__(cls, *args, **kwargs)
return cls._instance
C.__name__ = D.__name__
return C
@singleton
class Fire(object):
pass
Вы можете внедрить желаемое поведение в существующий объект класса, но это, на мой взгляд, излишне сложно, как это требуется (в Python 2.x)создание обертки метода, и вам также приходится иметь дело с ситуацией, в которой у декорируемого класса уже есть метод __new__()
.
Вы можете подумать, что можете написать метод __del__()
, чтобы разрешитьновый синглтон, который будет создан, когда нет ссылок на существующий экземпляр.Это не будет работать, потому что всегда есть внутренняя ссылка класса на экземпляр (например, Fire._instance
), поэтому __del__()
никогда не вызывается.Если у вас есть синглтон, он останется здесь.Если вам нужен новый синглтон после того, как вы закроете старый, , вы, вероятно, на самом деле не хотите синглтон , а скорее что-то еще. менеджер контекста может быть возможен.
"Синглтон", который может быть восстановлен при определенных обстоятельствах, будет для меня действительно странным и неожиданным поведением, и я бы посоветовал противЭто.Тем не менее, если вы действительно этого хотите, вы можете сделать self.__class__._instance = None
в вашем close_()
методе.Или вы можете написать отдельный метод для этого.Это выглядит некрасиво, что уместно, потому что некрасиво.: -)
Я думаю, что ваш третий вопрос также возникает из-за того, что вы ожидаете, что синглтон каким-то образом исчезнет после того, как вы вызовете close_()
, когда вы не запрограммировали это поведение.