10.21
First, I don’t want to go into why/when to use Singletons (Or even if they have a valid use in python)… And yes, they do tend to be confusing no matter how they are implemented.
After looking around a bit, I wasn’t happy with many of the ways of creating a “singleton” in python, they all had some major flaw (That affected how I wanted to use it anyways).
Here’s the ways that I found while researching and my issues with them..
Using __metaclass__:
class Singleton(type): def __init__(cls, name, bases, dict): super(Singleton, cls).__init__(name, bases, dict) cls.instance = None def __call__(cls,*args,**kw): if cls.instance is None: cls.instance = super(Singleton, cls).__call__(*args, **kw) return cls.instance class MyClass(object): __metaclass__ = Singleton
My main problem with this method is that PyQt doesn’t allow for __metaclass__ because sip already defines a __metaclass__ for all PyQt objects. Otherwise this method seems fairly clean (Although metaclasses do seem to confuse many python users)
Overriding __new__:
class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__( cls, *args, **kwargs) return cls._instance
This one has a fairly glaring issue, and I don’t know why so many people recommend it.. This variant ends up with __init__ being called EVERY time you access it via Singleton(), which causes all sorts of issues. (You could track if __init__ has already run, but that’s even more crap your Singleton has to hack around in your class)
Creating a wrapper class (Too long to post here, here’s the recipe link):
http://code.activestate.com/recipes/52558-the-singleton-pattern-implemented-with-python/
this variant just seems messy to me, anytime __getattr__ and __setattr__ are being overwritten, there’s typically a better way (Not always of course).
Just raising an exception ( O.o ):
class Singleton: __single = None def __init__( self ): if Singleton.__single: raise Singleton.__single Singleton.__single = self
Well that’s just not what most people want… if you don’t have access to where the current instance is stored, you now have to understand how the singleton is implemented and access Singleton.__single in order to get it… Yuck.
It also means you have to check whenever you need it for an exception.
Overwriting itself and using __call__
class Singleton: def __call__(self): return self Singleton = Singleton()
I like how simple this variant is, it certainly seems closer to what I want. The issue with this singleton is that it can’t be subclassed, but otherwise it seems like fairly elegant python.
(You could subclass by using Singleton.__class__ I suppose, but that means other people subclassing you have to be aware of it. And their class won’t automatically behave like a singleton without them also overwriting their own name as well)
My version (Overwrite itself only on __init__):
class Singleton(object): def __init__(self): globals()[self.__class__.__name__] = self def __call__(self): return self
Subclasses don’t have to know about how the singleton is implemented, as long as the call the parent __init__ they will be a singleton as well (Even in another module):
class SubSingleton(Singleton): def __init__(self): super(SubSingleton, self).__init__()
And there you have it (If you want it anyways…)
No issues with subclassing, since at declaration time (And all the way up until Singleton() is called) your object is still the class, not the instance.
init is only called once, as it should be. And no metaclass is used, so PyQt is happy.
References from my research:
http://stackoverflow.com/questions/42558/python-and-the-singleton-pattern
http://code.activestate.com/recipes/52558-the-singleton-pattern-implemented-with-python/
Would this create this situation?
cls = Singleton # class
inst = cls() # an instance, inst != cls
cls = Singleton # now an instance
inst = cls() # inst == cls
I tend to stick with the class method version:
class Single(object):
__inst = None
def __init__(self,*args,**kwargs):
if self.__inst: raise RuntimeError(“Single instance already defined”)
# constructor stuff
@classmethod
def instantiate(*args, **kwargs):
if not self.__inst: self.__inst = cls(*args, **kwargs)
return self.__inst
It would be better if python had an equivalent of a private constructor, since this version has to rely on convention to force users not to instantiate directly…
Yeah it would result in something like that. Type comparisons after instantiation wouldn’t be possible in that way due to the class no longer being present in that name. In my use case, i really don’t care about that, but if you needed to type check I could see it being an issue.
I really dislike not using the constructor, and __init__ raising an Exception just bothers me… If there was a (clean) way of doing a module level property, it might be acceptable to do it that way, but from what I can tell there’s no elegant solution to that (Just hacking sys.modules).
I suppose you could do this and get the same result:
class Blah(object):
__inst = None
def __init__(self, *args, **kwargs):
if self.__inst: return
do_constructor_stuff()
def __new__(self, *args, **kwargs):
if not self._inst:
self._instance = super(Blah, self).__new__(self, *args, **kwargs)
return self._instance
and just abort out of the redundant constructor
Yeah I mentioned that above as well, although I don’t like the fact that __init__ is called twice, it does at least keep it from breaking.
Honestly, I have no idea why everyone complains so much about Singletons in python.
1) They should only be used rarely. Rarely!
2) Don’t bother creating a subclass to encourage their use or save 5 lines of clear code.
3) There are 10 ways to create singletons, all perfectly good (even if Singletons are bad), all of them are trivial to test and unlikely to be a source of any bug whatsoever.
Singletons in python are, to me, a terrible form of framework masturbation.
gui application need singleton, for example PyQt in maya
Hi Nathan,
I use your solution to the singleton pattern frequently.
But now I encountered a new situation where I want my singleton class to inherit from ‘dict’ rather than from ‘object’. I’m unsure how to modify the code – somehow, somewhere I need to initialice the dict – but how. Any chance you could clarify that.
Regards,
Manuel