Есть простой, элегантный способ определения одиночных чисел?
Кажется, есть много способов определить singletons в Python. Существует ли консенсусное мнение о Stack Overflow?
Ответы
Ответ 1
Я действительно не вижу необходимости, поскольку модуль с функциями (а не с классом) будет хорошо служить как одноэлементный. Все его переменные будут привязаны к модулю, который в любом случае не может быть повторно создан.
Если вы хотите использовать класс, не существует способа создания частных классов или частных конструкторов в Python, поэтому вы не можете защищать от нескольких экземпляров, кроме как только через соглашение, использующее ваш API. Я бы по-прежнему просто вводил методы в модуль и рассматривал модуль как синглтон.
Ответ 2
Здесь моя собственная реализация синглетонов. Все, что вам нужно сделать, это украсить класс; для получения синглтона вам необходимо использовать метод Instance
. Вот пример:
@Singleton
class Foo:
def __init__(self):
print 'Foo created'
f = Foo() # Error, this isn't how you get the instance of a singleton
f = Foo.instance() # Good. Being explicit is in line with the Python Zen
g = Foo.instance() # Returns already created instance
print f is g # True
И вот код:
class Singleton:
"""
A non-thread-safe helper class to ease implementing singletons.
This should be used as a decorator -- not a metaclass -- to the
class that should be a singleton.
The decorated class can define one '__init__' function that
takes only the 'self' argument. Also, the decorated class cannot be
inherited from. 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 'TypeError' being raised.
"""
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.
"""
try:
return self._instance
except AttributeError:
self._instance = self._decorated()
return self._instance
def __call__(self):
raise TypeError('Singletons must be accessed through 'instance()'.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)
Ответ 3
Вы можете переопределить метод __new__
следующим образом:
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(
cls, *args, **kwargs)
return cls._instance
if __name__ == '__main__':
s1 = Singleton()
s2 = Singleton()
if (id(s1) == id(s2)):
print "Same"
else:
print "Different"
Ответ 4
Несколько иной подход к реализации синглтона в Python - это borg pattern от Alex Martelli (сотрудник Google и гений Python).
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
Поэтому вместо того, чтобы заставить все экземпляры иметь одинаковый идентификатор, они делят состояние.
Ответ 5
Подход модуля работает хорошо. Если мне абсолютно нужен синглтон, я предпочитаю подход Metaclass.
class Singleton(type):
def __init__(cls, name, bases, dict):
super(Singleton, cls).__init__(name, bases, dict)
cls.instance = None
def __call__(cls,*args,**kw):
if cls.instance is None:
cls.instance = super(Singleton, cls).__call__(*args, **kw)
return cls.instance
class MyClass(object):
__metaclass__ = Singleton
Ответ 6
См. Эту реализацию от PEP318, реализуя шаблон singleton с помощью декоратора:
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
Ответ 7
Как говорится в принятом ответе, самый идиоматический способ - просто использовать модуль.
Имея это в виду, здесь доказательство понятия:
def singleton(cls):
obj = cls()
# Always return the same object
cls.__new__ = staticmethod(lambda cls: obj)
# Disable __init__
try:
del cls.__init__
except AttributeError:
pass
return cls
Подробнее о __new__
см. модель данных Python.
Пример:
@singleton
class Duck(object):
pass
if Duck() is Duck():
print "It works!"
else:
print "It doesn't work!"
Примечания:
-
Для этого вам нужно использовать классы нового стиля (исходя из object
).
-
Синтаксис инициализируется, когда он определен, а не в первый раз, когда он использовался.
-
Это просто игрушечный пример. Я никогда не использовал это в производственном коде и не планирую.
Ответ 8
Однажды я написал синглтон в Python. Я использовал класс, в котором все функции-члены имели декоратор класса.
class foo:
x = 1
@classmethod
def increment(cls, y = 1):
cls.x += y
Ответ 9
Документация Python охватывает это:
class Singleton(object):
def __new__(cls, *args, **kwds):
it = cls.__dict__.get("__it__")
if it is not None:
return it
cls.__it__ = it = object.__new__(cls)
it.init(*args, **kwds)
return it
def init(self, *args, **kwds):
pass
Я бы, вероятно, переписал его, чтобы больше походить на это:
class Singleton(object):
"""Use to create a singleton"""
def __new__(cls, *args, **kwds):
"""
>>> s = Singleton()
>>> p = Singleton()
>>> id(s) == id(p)
True
"""
self = "__self__"
if not hasattr(cls, self):
instance = object.__new__(cls)
instance.init(*args, **kwds)
setattr(cls, self, instance)
return getattr(cls, self)
def init(self, *args, **kwds):
pass
Это должно быть относительно чистым, чтобы расширить это:
class Bus(Singleton):
def init(self, label=None, *args, **kwds):
self.label = label
self.channels = [Channel("system"), Channel("app")]
...
Ответ 10
Я очень неуверен в этом, но в моем проекте используются "условные одиночные игры" (не принудительные синглтоны), то есть, если у меня есть класс под названием DataController
, я определяю его в том же модуле:
_data_controller = None
def GetDataController():
global _data_controller
if _data_controller is None:
_data_controller = DataController()
return _data_controller
Это не изящно, так как это полные шесть строк. Но все мои синглеты используют этот шаблон, и он по крайней мере очень явный (что является питоновым).
Ответ 11
В блоге Google Testing есть несколько интересных статей, в которых обсуждаются причины, по которым синглтон может быть плохим, и являются анти-шаблонами:
Ответ 12
Создание декоратора singleton (ака аннотации) является элегантным способом, если вы хотите украсить (аннотировать) классы в будущем. Затем вы просто ставите @singleton перед определением вашего класса.
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
Ответ 13
Вот пример из Peter Norvig Python IAQ Как сделать шаблон Singleton в Python? (Вы должны использовать функцию поиска вашего браузера чтобы найти этот вопрос, нет прямой ссылки, извините)
Также у Брюса Эккеля есть еще один пример в его книге Мышление в Python (опять же нет прямой ссылки на код)
Ответ 14
Я думаю, что форсирование класс или экземпляр, который является синглом, является излишним. Лично мне нравится определять нормальный экземпляр класса, полу-частную ссылку и простую функцию factory.
class NothingSpecial:
pass
_the_one_and_only = None
def TheOneAndOnly():
global _the_one_and_only
if not _the_one_and_only:
_the_one_and_only = NothingSpecial()
return _the_one_and_only
Или если нет проблемы с созданием экземпляра при первом импортировании модуля:
class NothingSpecial:
pass
THE_ONE_AND_ONLY = NothingSpecial()
Таким образом, вы можете писать тесты против свежих экземпляров без побочных эффектов, и нет необходимости в том, чтобы посыпать модуль глобальными операторами, и при необходимости вы можете получить варианты в будущем.
Ответ 15
Шаблон Singleton, реализованный с помощью Python, предоставлен ActiveState.
Похоже, что трюк заключается в том, чтобы поставить класс, который должен иметь только один экземпляр внутри другого класса.
Ответ 16
Хорошо, синглтон может быть хорошим или злым, я знаю. Это моя реализация, и я просто расширяю классический подход, чтобы внедрить кеш внутри и создавать множество экземпляров другого типа или, например, много экземпляров одного типа, но с разными аргументами.
Я назвал его Singleton_group, потому что он группирует аналогичные экземпляры вместе и предотвращает создание объекта того же класса с одинаковыми аргументами:
# Peppelinux cached singleton
class Singleton_group(object):
__instances_args_dict = {}
def __new__(cls, *args, **kwargs):
if not cls.__instances_args_dict.get((cls.__name__, args, str(kwargs))):
cls.__instances_args_dict[(cls.__name__, args, str(kwargs))] = super(Singleton_group, cls).__new__(cls, *args, **kwargs)
return cls.__instances_args_dict.get((cls.__name__, args, str(kwargs)))
# It a dummy real world use example:
class test(Singleton_group):
def __init__(self, salute):
self.salute = salute
a = test('bye')
b = test('hi')
c = test('bye')
d = test('hi')
e = test('goodbye')
f = test('goodbye')
id(a)
3070148780L
id(b)
3070148908L
id(c)
3070148780L
b == d
True
b._Singleton_group__instances_args_dict
{('test', ('bye',), '{}'): <__main__.test object at 0xb6fec0ac>,
('test', ('goodbye',), '{}'): <__main__.test object at 0xb6fec32c>,
('test', ('hi',), '{}'): <__main__.test object at 0xb6fec12c>}
Каждый объект несет одноэлементный кеш... Это может быть зло, но для некоторых он отлично работает:)
Ответ 17
Будучи относительно новым для Python, я не уверен, что такое самая распространенная идиома, но самая простая вещь, о которой я могу думать, - это просто использовать модуль вместо класса. То, что было бы экземпляром методов в вашем классе, становится просто функциями в модуле, и любые данные просто становятся переменными в модуле, а не членами класса. Я подозреваю, что это пифонический подход к решению проблемы, с которой люди используют одиночные игры.
Если вы действительно хотите использовать одноэлементный класс, существует разумная реализация, описанная в впервые попавшая в Google для "Singleton" Python, в частности:
class Singleton:
__single = None
def __init__( self ):
if Singleton.__single:
raise Singleton.__single
Singleton.__single = self
Это похоже на трюк.
Ответ 18
class Singleton(object[,...]):
staticVar1 = None
staticVar2 = None
def __init__(self):
if self.__class__.staticVar1==None :
# create class instance variable for instantiation of class
# assign class instance variable values to class static variables
else:
# assign class static variable values to class instance variables
Ответ 19
Мое простое решение, основанное на значении параметров функции по умолчанию.
def getSystemContext(contextObjList=[]):
if len( contextObjList ) == 0:
contextObjList.append( Context() )
pass
return contextObjList[0]
class Context(object):
# Anything you want here
Ответ 20
Синглтонский брат
Я полностью согласен с staale, и я оставляю здесь образец создания одиночного брата:
class void:pass
a = void();
a.__class__ = Singleton
a
будет сообщать о себе как о том же классе, что и singleton, даже если он не похож на него. Таким образом, одиночные игры, использующие сложные классы, заканчиваются в зависимости от того, что мы с ними не много.
Таким образом, мы можем иметь тот же эффект и использовать более простые вещи, такие как переменная или модуль. Тем не менее, если мы хотим использовать классы для ясности и потому что в Python класс является объектом, значит, у нас уже есть объект (нет и экземпляр, но он будет делать точно так же).
class Singleton:
def __new__(cls): raise AssertionError # Singletons can't have instances
У нас есть хорошая ошибка утверждения, если мы пытаемся создать экземпляр, и мы можем хранить на выводах статические члены и вносить изменения в них во время выполнения (я люблю Python). Этот объект так же хорош, как и другие о половинах братьев (вы все равно можете их создать, если хотите), однако из-за простоты он будет стремиться быстрее.
Ответ 21
class Singeltone(type):
instances = dict()
def __call__(cls, *args, **kwargs):
if cls.__name__ not in Singeltone.instances:
Singeltone.instances[cls.__name__] = type.__call__(cls, *args, **kwargs)
return Singeltone.instances[cls.__name__]
class Test(object):
__metaclass__ = Singeltone
inst0 = Test()
inst1 = Test()
print(id(inst1) == id(inst0))
Ответ 22
В тех случаях, когда вы не хотите, чтобы решение на основе метакласса было выше, и вам не нравится простой подход, основанный на декораторе (например, потому что в этом случае статические методы для одноэлементного класса не будут работать), это компромиссные работы:
class singleton(object):
"""Singleton decorator."""
def __init__(self, cls):
self.__dict__['cls'] = cls
instances = {}
def __call__(self):
if self.cls not in self.instances:
self.instances[self.cls] = self.cls()
return self.instances[self.cls]
def __getattr__(self, attr):
return getattr(self.__dict__['cls'], attr)
def __setattr__(self, attr, value):
return setattr(self.__dict__['cls'], attr, value)