Palavras-chave: Python, Design Patterns, Padrões de Projeto, OOP, POO
Um Singleton é um dos padrões de projeto descrito no famoso livro “Design Patterns” escrito pela GoF (Gang of Four) e o seu funcionamento é bastante simples: uma classe é chamada de Singleton quando ela permite apenas uma única instância.
A maneira de se implementar um Singleton descrita no livro consiste em definir um método get_instance() na classe que ficará responsável por criar a primeira instância e a partir daí retorná-la sempre que for chamada.
Mas a natureza dinâmica de Python e seu sistema de meta-classes permitem que se crie uma classe chamada Singleton genérica que podemos usar como super-classe dos nossos próprios Singletons:
class Singleton(object): def __new__(cls, *args, **kwargs): if '_inst' not in vars(cls): cls._inst = type.__new__(cls, *args, **kwargs) return cls._inst
Agora, para que a sua classe se transforme em Singleton basta apenas derivá-la desta classe e não é mais necessário implementar o método get_instance(). O seu uso ficaria assim:
class MeuSingleton(Singleton): pass a = MeuSingleton() b = MeuSingleton() print a is b # imprimirá True, pois trata-se da mesma instância
Essa dica faz parte do livro Python Cookbook e foi escrita por Jürgen Hermann. No livro você poderá encontrar as explicações detalhadas sobre essa classe e mais uma série de outras dicas interessantes sobre diversos assuntos.
Oi Osvaldo! Parece que há um pequenino erro no código!
Deve ser:
cls._inst = object.__new__(cls, *args, **kwargs)
ao invés de:
cls._inst = type.__new__(cls, *args, **kwargs)
Uma outra maneira de se criar singletons em Python é instaciar as classes(que serão singletons) em um módulo separado. Sempre que se precisar das mesmas é só importar o módulo. Como os módulos são compilados apenas uma vez, quando importados, então temos nassas singletons.
yguaratã,
O que faz o seu exemplo funcionar não é o fato do módulo ser __compilado__ apenas uma vez e sim que ele só é __lido/executado__ uma vez, sendo ele mesmo um singleton.
É o que meu comentário diz: “…quando importados…”
Olá Osvaldo,
tomei a liberdade de usar este código que você postou na minha aplicação e hoje me deparei com uma situação interessante:
quando crio uma nova instância, a parte do método __new___ funciona normalmente mas ainda assim o método __init__ da classe é chamado… É possível evitar isso ?
Obrigado,
Tkm
O melhor exemplo de implementação de singleton que eu encontrei foi no texto sobre meta-classes do GVR: http://www.python.org/download/releases/2.2.3/descrintro/
Não sei se vai ficar direito no comentário aqui do wordpress, mas aí vai a minha implementação com base no exemplo do texto:
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.__1st_init__(*args, **kwds)
return it
def __1st_init__(self, *args, **kwds):
pass
class FoobarTon(Singleton):
def __1st_init__(self):
print “calling __1st_init__”
self.x = 0
def __init__(self):
print “calling __init__”
def inc(self):
self.x += 1
print “FoobarTon”
f1 = FoobarTon()
f2 = FoobarTon()
f3 = FoobarTon()
f1.inc();
f2.inc();
f3.inc();
print “f1 is fs2: %s” % str(f1 is f2)
print “f1 is fs3: %s” % str(f1 is f3)
print “f3.x: %d” % f3.x
Anyway, esse código tá no meu junk-code: http://svn.ademar.org/code/trunk/junk-code/ (é o último exemplo do singleton_vs_borg.py).