¿Existe una forma sencilla y elegante de definir singletons? [duplicar]
Parece haber muchas formas de definir singletons en Python. ¿Existe una opinión consensuada sobre Stack Overflow?
Realmente no veo la necesidad, ya que un módulo con funciones (y no una clase) serviría bien como singleton. Todas sus variables estarían vinculadas al módulo, del que de todos modos no se podrían crear instancias repetidas.
Si desea utilizar una clase, no hay forma de crear clases privadas o constructores privados en Python, por lo que no puede protegerse contra múltiples instancias, excepto simplemente mediante convención en el uso de su API. Todavía simplemente pondría métodos en un módulo y consideraría el módulo como el singleton.
Aquí está mi propia implementación de singletons. Todo lo que tienes que hacer es decorar la clase; para obtener el singleton, debes usar el Instance
método. He aquí un ejemplo:
@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
Y aquí está el código:
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)
Puedes anular el __new__
método de esta manera:
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"
Un enfoque ligeramente diferente para implementar el singleton en Python es el patrón borg de Alex Martelli (empleado de Google y genio de Python).
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
Entonces, en lugar de obligar a todas las instancias a tener la misma identidad, comparten estado.