The following class shows how to implement the singleton pattern[1] in Python. A singleton is a class that makes sure only one instance of it is ever created. Typically such classes are used to manage resources that by their very nature can only exist once.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | class Singleton:
""" A python singleton """
class __impl:
""" Implementation of the singleton interface """
def spam(self):
""" Test method, return singleton id """
return id(self)
# storage for the instance reference
__instance = None
def __init__(self):
""" Create singleton instance """
# Check whether we already have an instance
if Singleton.__instance is None:
# Create and remember instance
Singleton.__instance = Singleton.__impl()
# Store instance reference as the only member in the handle
self.__dict__['_Singleton__instance'] = Singleton.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
# Test it
s1 = Singleton()
print id(s1), s1.spam()
s2 = Singleton()
print id(s2), s2.spam()
# Sample output, the second (inner) id is constant:
# 8172684 8176268
# 8168588 8176268
|
This implementation hides the singleton interface in an inner class and creates exactly one instance of the inner class. The outer class is a handle to the inner class and delegates any requests to it. While the id() of the handle objects changes, the id() of the inner class which implements the singleton behaviour is constant.
Of course, the inner class is not REALLY hidden, like anything in Python. But you have to invest extra effort to break into the singleton.
This is related to the "Automatic delegation as an alternative to inheritance" recipe.
[1] Gamma, Helm, et al, "Design Patterns - Elements of Reusable Object-Oriented Software". Addison-Wesley, 1995, ISBN 0-201-63361-2.
RE: Singleton right behavior. all id's in the sample output must be equal!
Try this:
A simpler singleton. Phooey, both of these examples are too complicated. :-)
Alas, this isn't perfect. If for some reason you need to subclass Spam, you obviously can't. But I think this is sufficient for most people's needs.
Since Python doesn't have any notion of class/static methods, it isn't possible to build singletons "the right way". Every workable solution will be a compromise of some sort.
Obfuscated singleton. ps: Of course this is possible too...
Singleton example.
This singleton implementation draws from 'static method/class method'
examples by Thomas Heller and Clark Evans.
Subclassing is possible, but ugly! Inheritance is possible and can be documented as such if you use such an idiom to implement the Singleton.
Small correction. This does only work if you call 'getInstance()' before the constructor ; if not, you will get a much different instances as you wish until 'getInstance()' get called:
If you want to make sure that the constructor is not called more than once, 'TestSingleton.__init__' should read:
(last line added)
Much easier solution. I found some of the previously mentioned ideas a bit too complicated. Here's my implementation:
=====
Singletons with inheritance.
good one. you should put that one as a recipe.
And what about threads? Given implementations of Singleton pattern aren't thread-safe.
Some more stuff is needed to reach that point. Something like the
following should be used:
There's a version that's been evolving for about 5 years at http://www.garyrobinson.net/2004/03/python_singleto.html. It's pretty complete and has benefitted from a fair amount of feedback and suggestions at that location. It's threadsafe and includes unit tests.
I tried to post it here, but even leaving out the unit tests, it's longer than the 3000 char limit in this comment area.
Oops, the source at the link above was accidentally an out of date version until now (without the thread-safety and some other improvements) until now. Fixed now.
Code: