Como Implementar O Padrão de Projeto Singleton em Python
Rafael Marques 14 de janeiro de 2019 Design Patterns, Programação, Python Nenhum comentário
Este artigo tem por finalidade apresentar a definição, uso e melhores práticas do padrão de projeto Singleton em Python, a fim de que possamos saber quando e porque utilizá-lo corretamente.
2 O Que É O Singleton?
3 O Padrão de Projeto Singleton Em Python
4 Singleton Utilizando O __new__
5 Função Como Singleton
6 Módulos e Funções como Singletons
O Padrão de Projeto Singleton em Python (Este artigo)
O Padrão de Projeto Adapter em Python
O Que É O Singleton?
Class diagram exemplifying the singleton pattern.
O padrão de projeto Singleton tem como objetivo garantir que exista apenas uma instância de um determinado objeto em sua aplicação.
Ele é comumente implementado utilizando um construtor privado, e um método estático que retorna uma instância da classe.
Como você pode imaginar, o padrão de projeto Singleton em Python pode assumir diversas formas.
Tentando chegar próximo das implementações padrões do Singleton em outras linguagens, podemos implementar algo do tipo:
class Singleton: _instance = None @staticmethod def get_instance(): if Singleton._instance == None: Singleton._instance = Singleton() return Singleton._instance
if Singleton._instance == None:
Singleton._instance = Singleton()
E podemos testar e conferir o resultado abaixo:
if __name__ == '__main__': singleton_1 = Singleton().get_instance() singleton_2 = Singleton().get_instance() singleton_3 = Singleton.get_instance() singleton_4 = Singleton.get_instance() print(singleton_1 is singleton_2) print(singleton_3 is singleton_4) print(singleton_1 is singleton_3)
singleton_1 = Singleton().get_instance()
singleton_2 = Singleton().get_instance()
singleton_3 = Singleton.get_instance()
singleton_4 = Singleton.get_instance()
print(singleton_1 is singleton_2)
print(singleton_3 is singleton_4)
print(singleton_1 is singleton_3)
Singleton Utilizando O __new__
Nós podemos também sobrescrever o magic method __new__ para obtermos um comportamento semelhante:
class Singleton: def say_hello(self): print('Hello from {}'.format(id(self))) def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) return cls._instance
print('Hello from {}'.format(id(self)))
E podemos testar o nosso exemplo tranquilamente:
if __name__ == '__main__': singleton_1 = Singleton() singleton_2 = Singleton() singleton_3 = Singleton() print(singleton_1 is singleton_2) print(singleton_1 is singleton_3) singleton_1.say_hello() singleton_2.say_hello() singleton_3.say_hello()
singleton_1 = Singleton()
singleton_2 = Singleton()
singleton_3 = Singleton()
singleton_1.say_hello()
singleton_2.say_hello()
singleton_3.say_hello()
Função Como Singleton
Nós podemos também criar uma classe "privada", e retornar a instância desta classe através de uma função, que "simularia" a criação do objeto:
class _Singleton: _instance = None def say_hello(self): print('Hello from {}'.format(id(self))) def Singleton(): if _Singleton._instance is None: _Singleton._instance = _Singleton() return _Singleton._instance
class _Singleton:
if _Singleton._instance is None:
_Singleton._instance = _Singleton()
return _Singleton._instance
Note que utilizamos o underscore para declarar a classe Singleton, já que no Python, nós não temos como definir algo diretamente como privado, da mesma maneira que outras linguagens como o Java permitem.
After all, we're all consenting adults here
Você pode conferir esta frase no seguinte link: https://mail.python.org/pipermail/tutor/2003-October/025932.html
Lembrem-se, o Python confia em você 😉
Módulos e Funções como Singletons
Ao criarmos um modulo com funções, nós podemos obter o mesmo comportamento de um singleton.
Vamos criar um módulo chamado smodule, e adicionar o código abaixo nele:
def this_is_like_a_singleton(): print('Hello from a singleton as a func module')
def this_is_like_a_singleton():
print('Hello from a singleton as a func module')
Ao utilizarmos o código, você poderá conferir que você pode importar este método várias vezes, e ele sempre sempre o mesmo:
from smodule import this_is_like_a_singleton as s1 from smodule import this_is_like_a_singleton as s2 if __name__ == '__main__': print(s1 is s2)
from smodule import this_is_like_a_singleton as s1
from smodule import this_is_like_a_singleton as s2
O padrão de projeto Singleton é bem conhecido, e também muito polêmico.
Há diversas críticas ao padrão, e muitos o consideram um anti-pattern.
Eu sinceramente nunca vi ninguém pessoalmente escrevendo um Singleton em Python, apesar de infelizmente já ter visto arquiteturas inteiras baseadas em singletons em outras linguagens, como o C# por exemplo.
Apesar de não ser comum a utilização , é de extrema importância conhecer o Singleton em Python para que você possa utilizá-lo, ou então, evitar a sua implementação durante o seu dia a dia.