Patrón Singleton en Python, con ejemplos


El patrón singleton es un patrón de creación (Creational Design Pattern) que tiene como objetivo garantizar que una clase sólo tenga una instancia y proporcionar un único punto de acceso a esa instancia. Este patrón suele ser utilizado en temas de logging (entre otros) donde solo queremos tener una una instancia del logger que centralice todo.

Existen muchas formas de implementar este patrón; vamos a comentar dos, una sencilla y otra que es interesante comentar por su parecido a Java, las cuales podemos consultar en:  http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Singleton.html.

Como se haría en Java

Podemos hacer una implementación similar a la que haríamos en Java, donde lo que estamos haciendo es declarar una clase interna privada (notada por __ ) ya que en python no podemos hacer constructores privados. En esta clase privada tenemos el método de inicialización (__init__), y el método que nos convierte el objeto a string (__str__) para que veamos que está siempre en la misma posición de memoria.

La primera vez que usamos el constructor (__new__) creamos la instancia ya que se cumple la condicion de que no tenemos instancia, y, el resto de veces no, simulando los constructores privados en java. También podemos ver que los getters y los setters son accedidos a través de __getattr__ y __setattr__ que llaman a los de la instancia.

# coding=utf-8
class SoyUnico(object):

    class __SoyUnico:
        def __init__(self):
            self.nombre = None

        def __str__(self):
            return `self` + ' ' + self.nombre

    instance = None

    def __new__(cls):
        if not SoyUnico.instance:
            SoyUnico.instance = SoyUnico.__SoyUnico()
        return SoyUnico.instance

    def __getattr__(self, nombre):
        return getattr(self.instance, nombre)

    def __setattr__(self, nombre, valor):
        return setattr(self.instance, nombre, valor)


ricardo = SoyUnico()
ricardo.nombre = "Ricardo Moya"
print(ricardo)
ramon = SoyUnico()
ramon.nombre = "Ramón Invarato"
print(ramon)

print(ricardo)
print(ramon)

Si lo ejecutamos:

<__main__.__SoyUnico instance at 0x7f9f88b24878> Ricardo Moya 
<__main__.__SoyUnico instance at 0x7f9f88b24878> Ramón Invarato 
<__main__.__SoyUnico instance at 0x7f9f88b24878> Ramón Invarato 
<__main__.__SoyUnico instance at 0x7f9f88b24878> Ramón Invarato 

Después de ejecutar el código vemos que lo que tenemos es siempre la variable en la misma posición de memoria (única instancia) y que sólo contiene el último valor porque solo hay una variable.

Forma sencilla

Podemos usar una forma simplificada, donde lo que hacemos la primera vez (usando el constructor nuevamente (__new__)) es instanciar la clase ya que la variable __instance es none y el resto de veces al tener valor, la devolvemos directamente.

# coding=utf-8
class SoyUnico(object):

    __instance = None
    nombre = None

    def __str__(self):
        return `self` + ' ' + self.nombre

    def __new__(cls):
        if SoyUnico.__instance is None:
            SoyUnico.__instance = object.__new__(cls)
        return SoyUnico.__instance

ricardo = SoyUnico()
ricardo.nombre = "Ricardo Moya"
print(ricardo)
ramon = SoyUnico()
ramon.nombre = "Ramón Invarato"
print(ramon)

print(ricardo)
print(ramon)

Ejecutando el código obtenemos:

<__main__.SoyUnico object at 0x7f53d6226050> Ricardo Moya 
<__main__.SoyUnico object at 0x7f53d6226050> Ramón Invarato 
<__main__.SoyUnico object at 0x7f53d6226050> Ramón Invarato 
<__main__.SoyUnico object at 0x7f53d6226050> Ramón Invarato 
Comparte esta entrada en:
Safe Creative #1401310112503
Patrón Singleton en Python, con ejemplos por "www.jarroba.com" esta bajo una licencia Creative Commons
Reconocimiento-NoComercial-CompartirIgual 3.0 Unported License.
Creado a partir de la obra en www.jarroba.com

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies

ACEPTAR
Aviso de cookies