[Tutor] What are "singletons" good for?

Steven D'Aprano steve at pearwood.info
Sun Sep 19 15:41:54 CEST 2010


On Sun, 19 Sep 2010 02:50:42 am Knacktus wrote:
> Hey all,
>
> the usual explanation for the usage of a Singleton goes like this:
>
> "Use a singleton if you want to make sure, that only one instance of
> a class exists."
>
> But now I ask myself: Why should I call the constructor of a class
> more than once if I only want one instance?

Why does int("spam") raise an exception that you can catch, instead of 
dumping core and crashing the machine? After all, if you don't want to 
crash the machine, just make sure you never call int() with something 
that isn't an integer.

Right?

No. We all know that no matter how much you intend to only call int() on 
strings which actually do represent integers, bugs do happen, so we 
have the language protect us from our mistakes. Likewise, you might 
intend to only call the constructor of a class once, and in a 200 line 
script you might even be confident of that fact, but in a 200,000 line 
program how confident will you be?

You might say "do a search of the source code, and if you see the 
constructor called twice, you know it's wrong" but of course there 
might be a legitimate reason to call the constructor from different 
places in the code, so long as only one of them is actually executed.


> After all, I decide in my code when to create an instance or when to
> pass an existing instance around.

Why should you have to decide? Why bother to track that yourself, when 
the class could track it for you?

Depending on your needs or philosophy, one tactic is to have the class 
explicitly tell you when you're trying to initialise a second instance, 
by raising an exception. Python does that with some singletons:

>>> type(None)()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot create 'NoneType' instances

And the same for NotImplemented. Personally, I don't understand that 
tactic. I prefer the tactic used by the pair of singletons True and 
False:

>>> bool() is False
True

No matter how many times you call bool(), it will always return one of 
the two singleton instances True or False. Imported modules are the 
same -- every time you import a module, Python gives you the same 
module instance. So if you need singleton behaviour, a module gives you 
that for free.


> Example in pseudocode:
>
> class Session(object):
>      """Hold a dictionary of ident_to_data_objects"""
>
>      def __init__(self, ident_to_data):
>          self.ident_to_data = ident_to_data
>
> Now, that would be a typical "singleton" use case. I want one 
> instance of this class application-wide. For example in a View class:
>
> class View(object):
>      """Create fancy views"""
>
>      def __init__(self, session):
>          self.session = session

If there's only ever one session, can't possibly be a second, then why 
make it an attribute of the view instance? You might have 30 views, so 
why pretend that they could have 30 different sessions?

Better to inject the session into the View class itself, as a class 
attribute:

class View(object):
    """Create fancy views"""
    session = None
    def __init__(self, session=None):
        if self.session is None:
            self.__class__.session = session
        elif session is not None:
            raise ValueError('cannot use two sessions')

But why pretend that you might have multiple View-like classes, with 
different sessions? Since you have the invariant that there can only 
ever be one session, you can't allow this:

class MyView(View):
    session = another_session()

Since that's prohibited, don't pretend it's allowed. You might as well 
make session a global variable, and stop pretending to be more virtuous 
than you actually are.

And that's the problem -- singletons are often (not always, but often) 
just a sop to the idea that global variables are bad. They are, but 
disguising them as a singleton object doesn't make them less bad. It's 
better to think really hard about *why* you want only one instance of a 
class, whether it's really necessary, and if so, whether an alternative 
such as the Borg pattern would be better.

http://code.activestate.com/recipes/66531/


> In my code I use these classes like this:
>
> class MainApp(object):
>      """Do some stuff with the data_objects"""
>
>      def __init__(self):
>          self.session = Session()
>          self.view = View(self.session)

Since every MainApp instance creates it's own independent session 
object, no, there's no singleton. It's not a singleton if you merely 
*happen* to only create one instance. It's only a singleton if you 
*can* only create one instance (or at least, one instance with each 
specific value).

E.g. you can create multiple lists with the same value but different 
identity:

>>> a = [1, 2]
>>> b = [1, 2]
>>> a is b
False

so lists are not singletons. But you can't create multiple module 
objects with the same value and different identity:

>>> import math
>>> import math as another_math
>>> math is another_math
True

So even though there is are many different modules, we call them 
singletons.


> Would a singleton usage in the View class look like that?
>
> class View(object):
>      """Create fancy views"""
>
>      def __init__(self):
>          self.session = Session()

Again, there's nothing "singleton" about this. Apart from modules, you 
don't get singletons for free in Python, you have to work at it. One 
way is this:

# Untested
class Singleton(object):
    _instance = None
    def __new__(cls):
        if cls._instance is not None:
            # raise TypeError('cannot make a second instance')
            # but this might be better:
            return cls._instance
        else:
            inst = object.__new__(cls)
            cls._instance = inst
            return inst



> What's the point? 

Good question. It seems to me that the Singleton design pattern has the 
wrong focus, and so it actually isn't useful or necessary in most of 
the cases that people use it. In my opinion, it's mostly a gimmick.

Some exceptions -- the None singleton is useful, because we *do* care 
about identity. None has no state, it has no attributes or useful 
methods, the *only* thing we care about is identity -- something either 
is None or it isn't. Same with NotImplemented, True, False and a 
handful of other objects. So Singleton is valid for them.

Modules, on the other hand, could just have easily be implemented as the 
Borg pattern -- you might have two, three, a thousand instances of the 
math module, so long as they all share the same state rather than being 
copies, it doesn't matter. Ensuring that there's only one instance of 
the math module is a tiny memory optimization, but other than that, it 
would make no real difference.



> Is it the spared typing when instanciating a lot of 
> View classes (I wouldn't need to pass the session to the
> constructor). Or are there some more advantages (instead of passing
> the same instance aorund)? Also, what would you guys consider as
> disadvantages?

The biggest disadvantage of singletons is that they're often just 
disguised global variables. Instead of writing:

# Globals
default_page_size = "A4"
default_left_margin = 2  # cm
default_right_margin = 2
# etc.

people have a tendency to do this:


MyApp(defaults=SingletonPageSettings("A4", 2, 2))


and think this makes their code "better". (I blame the Go4 for making a 
religion out of design patterns which exist only to work around Java's 
limitations.) But it's just a disguised global record, with exactly the 
same problems as ordinary globals.

The second biggest problem is that, invariably, if you think something 
needs to be a singleton today, tomorrow you'll wish you had two of 
them. You have a singleton Desktop object in your window manager, and 
then you realise that there's no reason not to have multiple desktops. 
Your word processor has a singleton Printer config, but then you buy a 
second printer. Even if you really do want a single instance, say of 
your MainApp object, sometimes it's useful to have a second one for 
debugging. So in Java land, programmers often try to bypass the 
singleton code so they can defeat the original designer who made it a 
singleton.


> Another question related to this topic is, if I would use a module as
> a singleton (as suggested by Steve and other), how would I import it
> the instances of a class? Maybe like this?
>
> class View(object):
>      """Create fancy views"""
>
>      import session
>
>      def do_something(self, ident):
>          self.certain_data_object = session.ident_to_data[ident]

Almost -- you would have to refer to self.session, not just session. 
Other than that, you could do it, of course, but it's simpler to stick 
with this:


import session

class View(object):
    """Create fancy views"""
    def do_something(self, ident):
        self.certain_data_object = session.ident_to_data[ident]




-- 
Steven D'Aprano


More information about the Tutor mailing list