Parece que hay muchas formas de definir singletons en Python. ¿Existe una opinión consensuada sobre Stack Overflow?¿Existe alguna manera simple y elegante de definir singletons?
Respuesta
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, que de todos modos no podría ser instanciado repetidamente.
Si desea utilizar una clase, no hay forma de crear clases privadas o constructores privados en Python, por lo que no puede protegerse contra varias instancias de instancias que no sean solo mediante convenciones en el uso de su API. Todavía pondría métodos en un módulo y consideraría el módulo como singleton.
¿No podría el constructor simplemente comprobar si ya se ha creado una instancia y lanzar una excepción si lo ha sido? – Casebash
Esto está bien siempre que no necesite utilizar la herencia como parte de su diseño, en cuyo caso la mayoría de las respuestas siguientes son más adecuadas –
Para acceder a las "propiedades del módulo" de la manera correcta, consulte: http: // stackoverflow .com/questions/6841853/python-accessing-module-scope-vars/6842257 # 6842257 –
Siendo relativamente nuevo en Python no estoy seguro de cuál es el modismo más común, pero lo más simple que puedo pensar es simplemente usar un módulo en lugar de una clase. Lo que habrían sido los métodos de instancia en su clase se convertirán en funciones en el módulo y cualquier dato simplemente se convierte en variables en el módulo en lugar de miembros de la clase. Sospecho que este es el enfoque pitónico para resolver el tipo de problema para el que las personas usan singletons.
Si realmente quieres una clase Singleton, hay una aplicación razonable descrito en el first hit on Google para "Singleton Python", en concreto:
class Singleton:
__single = None
def __init__(self):
if Singleton.__single:
raise Singleton.__single
Singleton.__single = self
que parece hacer el truco.
No es bueno, solo plantea una excepción en lugar de devolver la instancia de singleton – pylover
Aquí se muestra un ejemplo de calidad del aire interior del pitón de Peter Norvig How do I do the Singleton Pattern in Python? (Debe utilizar la función de búsqueda de su navegador para encontrar esta pregunta, no existe una relación directa, lo siento)
también Bruce Eckel tiene otro ejemplo en su libro Thinking in Python (otra vez no hay un enlace directo al código)
+1 por mencionar la función de búsqueda del navegador. –
Gracias por el enlace. Por qué una respuesta tan buena tiene solo 4 votos positivos (incluido yo). – Wilbeibi
Un enfoque ligeramente diferente para implementar el singleton en Python es el borg pattern de Alex Martelli (empleado de Google y genio de Python).
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
En lugar de forzar a todas las instancias a tener la misma identidad, comparten el estado.
También conocido como monostate. Posiblemente más malvado que singleton. –
-1, ¿cuál es el punto? – hasen
No es Singleton en absoluto. –
El enfoque del módulo funciona bien. Si necesito absolutamente un singleton, prefiero el enfoque 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
Este patrón está en contra del "Principio de responsabilidad única" (http://c2.com/cgi/wiki?SingleResponsibilityPrinciple). Vea el punto (2) en http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx. – haridsv
@haridsv No estoy de acuerdo. El hecho de que la clase es un singleton __is__ abstraído en la implementación de metaclase - la clase en sí misma no sabe o le importa que sea un singleton, ya que no está a cargo de hacer cumplir ese requisito, la metaclass sí lo está. El método a continuación es claramente una violación, sin embargo, como usted nota. El método de la clase base está en algún punto intermedio. – agf
el problema con esto es que puedes crear instancias múltiples de 'MyClass' a través de' deepcopy'. Si ejecuta 'from copy import deepcopycopy como dcp; m1 = MyClass(); m2 = dcp (m1); print m1 es m2', obtendrás 'False'. ¿Conoces alguna forma de evitarlo? –
La única vez que escribí un producto único en Python que utiliza una clase donde todas las funciones miembro tenían el decorador classmethod.
class foo:
x = 1
@classmethod
def increment(cls, y = 1):
cls.x += y
Me gusta este enfoque, pero hay un pequeño inconveniente. Al menos con Python 2.6, no puedes hacer que métodos como '__len__' o' __getitem__' funcionen como classmethods, por lo que no tienes tanta flexibilidad para personalizar como lo harías con un objeto. Como a menudo quiero usar un Singleton como una colección de datos, eso es un poco decepcionante. –
Me parece que esto no es más que el envoltorio de un montón de cosas en un espacio de nombres ...no es que haya nada de malo en eso, algunos incluso han dicho que piensan que son una gran idea ('import this') - es solo que este enfoque no es mucho más que simple y parece muy cercano al uso de variables globales que generalmente se considera una mala práctica de ingeniería. – martineau
@martineau Sugiero que usar un singleton es muy similar al uso de variables globales sin importar cómo se implemente. –
The Singleton Pattern implemented with Python cortesía de ActiveState.
Parece que el truco es poner la clase que se supone que solo tiene una instancia dentro de otra clase.
También hay algunos artículos interesantes en el blog de Google Testing, discutiendo qué Singleton son/puede ser malo y son un anti-patrón:
Puse sus enlaces en líneas separadas para que no se fusionen todos en uno –
No estoy muy seguro de esto, pero mi proyecto usa 'convention singletons' (no forzado singletons9, es decir, si tengo una clase cal conducido DataController, que define esta en el mismo módulo:
_data_controller = None
def GetDataController():
global _data_controller
if _data_controller is None:
_data_controller = DataController()
return _data_controller
No es elegante, ya que es un total de seis líneas. Pero todos mis singletons usan este patrón, y al menos es muy explícito (que es pitónico).
de acuerdo. Y debería haber leído ** todas ** las respuestas antes de publicar las mías ... –
+1 En Python debería ser todo sobre convenciones (porque generalmente se puede hackear los límites impuestos). Personalmente, prefiero un classmethod y una variable de clase para acceder y almacenar la instancia, por lo que no tiene que usar 'global'. (Generalmente desaconsejo el uso de 'global', aunque este es uno de los pocos casos de uso en los que es aceptable). – schlamar
se puede anular el método __new__
así:
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"
ADVERTENCIA: Si __new __() devuelve una instancia de cls, entonces se invocará el método __init __() de la nueva instancia como __init __ (self [, ...]), donde self es la nueva instancia y los argumentos restantes son los mismos que se pasaron a __new __(). Si cualquier subclase de Singleton implementa __init __(), se llamará varias veces con el mismo self. Terminé usando una fábrica en su lugar. – alsuren
esto sería mejor usando una metaclase como la respuesta aquí: http://stackoverflow.com/a/33201/804147 – underrun
Esto da la siguiente advertencia - 'singleton.py:9: DeprecationWarning: objeto .__ nuevo __() no toma parameters' 'cls._instance = super (Singleton, cls) .__ nuevo __ (cls, * args, ** kwargs)' – Siddhant
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
Ver esta implementación de PEP318, implementando el patrón singleton con un decorador:
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
El problema con este decorador es que 'MyClass' ya no es una clase, p. super() no funciona, no funcionará classmethods etc: @Singleton class MiClase (BaseClass): def __init __ (self): super (MiClase, auto) .__ init __() – ithkuil
Parece que el decorador debería aplicarse al método __new__, en lugar de a la clase, para tratar el problema de la herencia. En ese punto, la legibilidad elegante del decorador se ve disminuida. O el decorador necesita fritz con la clase que está decorando para hacer que la función __new__ haga algo sensato. – F1Rumors
Creo que forzando una clase o una instancia para ser un singleton es overkill. Personalmente, me gusta definir una clase de instanciación normal, una referencia semiprivada y una función simple de fábrica.
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
O si no hay ningún problema con instanciar cuando el módulo está primero importada:
class NothingSpecial:
pass
THE_ONE_AND_ONLY = NothingSpecial()
esa manera usted puede escribir pruebas contra casos frescos, sin efectos secundarios, y no hay necesidad de rociar la módulo con declaraciones globales, y si es necesario, puede derivar variantes en el futuro.
Creo que es peor que exagerar. Forzar un comportamiento implícito simplemente no es pitónico. Y tengo más comentarios sobre la respuesta duplicada :-) http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python#comment19819697_1314783 – schlamar
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 método Instance
. 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)
En los casos en los que no desea que la solución basada en la metaclase arriba, y no le gusta lo simple decorador de la función enfoque basado en (por ejemplo, porque en ese caso los métodos estáticos de la clase Singleton no funcionarán), este compromiso funciona:
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)
Mi solución simple whic h se basa en el valor predeterminado de los parámetros de la función.
def getSystemContext(contextObjList=[]):
if len(contextObjList) == 0:
contextObjList.append(Context())
pass
return contextObjList[0]
class Context(object):
# Anything you want here
Creación de un decorador Singleton (también conocido como una anotación) es una manera elegante si quieres decorar (Anotar) clases en el futuro. Luego, simplemente coloca @singleton antes de la definición de su clase.
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
Me pregunto por qué no se votó al alza? Genial ... explique por qué y cómo se llama el método 'getinstance' –
Parece que ha copiado PEP318? –
Pero solo ayude a explicarlo ... –
OK, singleton podría ser bueno o malo, lo sé. Esta es mi implementación, y simplemente extiendo un enfoque clásico para introducir un caché dentro y producir muchas instancias de un tipo diferente o, muchas instancias del mismo tipo, pero con diferentes argumentos.
me llamaron Singleton_group, porque agrupa casos similares juntos y evitar que un objeto de la misma clase, con los mismos argumentos, se podría crear:
# Peppelinux's 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's 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>}
Cada objeto lleva la caché Singleton ... Este podría ser el mal, pero funciona muy bien para algunos :)
El Python documentation cubre lo siguiente:
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
que probablemente reescribirla a parecerse más a esto:
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
Debería ser relativamente limpia para extender este:
class Bus(Singleton):
def init(self, label=None, *args, **kwds):
self.label = label
self.channels = [Channel("system"), Channel("app")]
...
+1 por ser el único que menciona la implementación de Guido van Rossum. Sin embargo, su propia versión es incorrecta: no debe usar 'hasattr' y' getattr' dentro de '__new__' ya que ambos llaman' object .__ getattribute__' que a su vez busca su atributo '" __self __ "' en toda la jerarquía de clases en lugar de solo la clase actual. Si Guido usa '__dict__' para el acceso a los atributos, eso se debe a un motivo. Pruebe: 'clase A (GuidoSingleton): pase',' clase B (A): pase', 'clase C (SuSingleton): pase',' clase D (C): pase', 'imprima (A(), B(), C(), D()) '. Todas las subclases se refieren a la misma instancia con 'YourSingleton'! – Maggyero
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))
como dice el accepted answer, la forma más idiomática es simplemente utilizar un módulo.
Con esto en mente, aquí es una prueba de concepto:
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
Véase el Python data model para más detalles sobre __new__
.
Ejemplo:
@singleton
class Duck(object):
pass
if Duck() is Duck():
print "It works!"
else:
print "It doesn't work!"
Notas:
Tienes que utilizar las clases de nuevo estilo (derivan de
object
) para esto.El singleton se inicializa cuando está definido, en lugar de la primera vez que se usa.
Esto es solo un ejemplo de juguete. Nunca he usado esto en el código de producción, y no pienso hacerlo.
medio hermano
He intentado esto, pero tiene el error: TypeError: método no unido
Gracias por señalarlo. No tengo idea de por qué sucede eso, pero la versión editada debería funcionar en Python 2.7 y 3.3. –
Esto no es bueno, se llama al método '' __init __() '' cuando se define la clase (aunque es posible que desee esperar hasta la primera vez que se usa), y luego en cada llamada de '' Duck() ' '. – tiho
de Singleton
estoy completamente de acuerdo con Staale y dejo aquí una muestra de la creación de un medio hermano Singleton:
class void:pass
a = void();
a.__class__ = Singleton
a
reportarán ahora como siendo de la misma clase como singleton, incluso si no se parece. Así que los singletons que usan clases complicadas terminan dependiendo de que no nos equivoquemos mucho con ellos.
Siendo así, podemos tener el mismo efecto y usar cosas más simples como una variable o un módulo.Aún así, si queremos usar las clases para mayor claridad y porque en Python, una clase es un objeto, entonces ya tenemos el objeto (no e instancia, pero hará lo mismo).
class Singleton:
def __new__(cls): raise AssertionError # Singletons can't have instances
No tenemos un error de aserción agradable si tratamos de crear una instancia, y podemos almacenar en derivaciones miembros estáticos y realizar cambios en ellas en tiempo de ejecución (Me encanta Python). Este objeto es tan bueno como otros sobre medios hermanos (aún puedes crearlos si lo deseas), sin embargo, tenderá a correr más rápido debido a la simplicidad.
- 1. ¿Existe alguna manera elegante de actualizar jQuery lentamente?
- 2. ¿Existe alguna manera elegante de eliminar nulos al transformar una colección con Guava?
- 3. ¿Existe alguna manera elegante de establecer un valor predeterminado para una propiedad en C#?
- 4. Singletons y constantes
- 5. ¿Hay alguna manera elegante de escribir este código?
- 6. ¿Existe alguna forma más elegante de calcular x = (y/n) + (y% n? 1: 0)?
- 7. Manera elegante de iniciar y extender una matriz de javascript
- 8. ¿Hay alguna manera más elegante de agregar entradas anulables?
- 9. ¿Existe alguna manera fácil de usar InternalsVisibleToAttribute?
- 10. ¿Hay alguna manera simple de formatear decimales en T-SQL?
- 11. ¿Existe alguna manera simple de probar si un atributo de Moose es de solo lectura?
- 12. ¿Existe alguna manera más simple/mejor de poner un borde/contorno alrededor de mi TextView?
- 13. Pruebas de Singletons y subclases
- 14. ¿Existe alguna manera simple de determinar el tamaño de letra en C#?
- 15. ¿Manera elegante de eliminar filas huérfanas?
- 16. Globales y singletons en Python
- 17. Manera elegante de comparar secuencias
- 18. ¿Existe alguna manera más elegante de convertir años de dos dígitos a años de cuatro dígitos con lubridate?
- 19. ¿Hay alguna manera de definir una matriz constante en PHP?
- 20. ¿Existe una manera simple de comparar instancias de BufferedImage?
- 21. iOS Singletons y gestión de memoria
- 22. ¿Existe alguna manera elegante de convertir los códigos de idioma ISO 639-2 (3 letras) a Java Locales?
- 23. Rieles: ¿alguna forma elegante de manejar 404?
- 24. PowerShell: una manera elegante de crear cierres
- 25. ¿Manera elegante de escribir cadenas de pato, símbolos y matrices?
- 26. ¿Hay alguna manera simple de probar dos PNG por igualdad?
- 27. Rails 3 y will_paginate - manera elegante, cómo obtener total_pages
- 28. Manera elegante de validar los valores
- 29. ¿Existe alguna manera de extender las primeras migraciones de código?
- 30. ¿Hay alguna manera simple de concatenar dos BitArray (C# .NET)?
Error: línea 52 - Consenso no encontrado. – Homer6
[Singletons son mentirosos patológicos] (http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/), ¿no es así? –
"esta pregunta no encaja en nuestro formato de preguntas y respuestas" - Creo que esta no es una pregunta subjetiva, ¿hay alguna manera de hacer tales preguntas para que se ajuste al formato SO Q & A? – binithb