Translate

jueves, 15 de septiembre de 2016

El patrón SINGLETON o cómo obtener una instancia única de un proceso en Python

Un Singleton es un patrón de un proceso que solo tiene una instancia única y compartida entre todos los procesos que lo han instanciado y que se ejecutan en un hilo.

Se entiende mejor con un ejemplo sencillo (PYTHON 2.7) :


class A:
    # _instance es un atributo que conoce el Singleton
    _instance = None
    def foo(self):
        return id(self)

def Singleton(cls):
    # cls identifica la clase que solo debe instanciarse una vez por proceso
    if not cls._instance:
        print 'primera instancia del Singleton'
        cls._instance = cls()
    return cls._instance

# subclase A
class B(A):
    pass

b = Singleton(A)
c = Singleton(B)
d = Singleton(A)

print id(b),b.foo()
print id(c),c.foo()
print id(d),d.foo()


En este caso deseamos que la clase A se instancie una sola vez y esa instancia se comparta entre todos los procesos que la instanciarán posteriormente. Al instanciar la clase A con b=Singleton(A) creamos una primera instancia que se compartirá con las siguientes inicialización de la clase :  c= Singleton(B) y d=Singleton(A).

Posteriormente comprobamos el id de cada clase, siendo el mismo identificador :

primera instancia del singleton
32730128 32730128
32730128 32730128
32730128 32730128


A continuación crearemos otro ejemplo sobreescribiendo el método __new__ de una clase, convirtiéndola en Singleton :


class A(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(A, cls).__new__(cls, *args, **kwargs)
        return cls._instance

if __name__ == '__main__':
    b = A()
    c = A()
    if (id(b) == id(c)):
        print "Igual instancia"
    else:
        print "Diferente instancia"


En este caso, comprueba que también existe _instance como una variable de clase, igual que en ejemplo anterior, que almacena la instancia de clase. _instance se inicializa con la primera instancia de clase y devolverá el mismo valor de instancia a cada inicialización de clase que realizan los posteriores procesos.

A continuación mostramos otro ejemplo Singletón con decorador :


def singleton(cls):
    obj = cls()
    # Siempre devuelve el mismo objeto
    cls.__new__ = staticmethod(lambda cls: obj)
    # Desabilita __init__
    try:
        del cls.__init__
    except AttributeError:
        pass
    return cls

@singleton
class A(object):
    pass

if A() is A():
    print "Es lo mismo!"
else:
    print "Es diferente!"


Hasta aquí he querido poner algo de luz sobre el patrón SINGLETON.

No hay comentarios:

Publicar un comentario