Credit: Alex Martelli
You want to make sure that only one
instance of a class is ever created, but you don’t
care about the id
of the resulting instances, just
about their state and behavior.
Just about every application need related to Singleton is met by
ensuring that all instances share state and behavior, which is easier
and more flexible than fiddling with instance creation. Just subclass
the following Borg
class:
class Borg: _shared_state = {} def _ _init_ _(self): self._ _dict_ _ = self._shared_state
Ensure that Borg._ _init_ _
is called, just as you
always do for every base class’s constructor, and
you’re home free.
Here’s a typical example of Borg
use:
if _ _name_ _ == '_ _main_ _': class Example(Borg): def _ _init_ _(self, name=None): Borg._ _init_ _(self) if name is not None: self.name = name def _ _str_ _(self): return 'Example(%s)' % self.name a = Example('Lara') b = Example( ) print a, b c = Example('Boris') print a, b, c b.name = 'Marcel' print a, b, c
When running this module as a main script, the output is:
Example(Lara) Example(Lara) Example(Boris) Example(Boris) Example(Boris) Example(Marcel) Example(Marcel) Example(Marcel)
All instances of Example
share state, so any
setting of the name
attribute of any instance,
either in _ _init_ _
or directly, affects all
instances equally. However, note that their id
differs, so since we have not defined _ _eq_ _
and
_ _hash_ _
, they are distinct keys in a
dictionary. Thus, if we continued our sample code as follows:
adict = {} j = 0 for i in a, b, c: adict[i] = j j = j + 1 for i in a, b, c: print i, adict[i]
the output would be:
Example(Marcel) 0 Example(Marcel) 1 Example(Marcel) 2
If that’s not what you want, you can add _ _eq_ _
and _ _hash_ _
to the
Example
class or the Borg
class. For example, here are these special methods added to
Borg
:
class Borg: _shared_state = {} def _ _init_ _(self): self._ _dict_ _ = self._shared_state def _ _hash_ _(self): return 1 def _ _eq_ _(self, other): try: return self._ _dict_ _ is other._ _dict_ _ except: return 0
Now the example’s output concludes with:
Example(Marcel) 2 Example(Marcel) 2 Example(Marcel) 2
You might want to do this to simulate the existence of only one instance.
The Singleton design pattern has a catchy name, but the wrong focus for most purposes: on object identity, rather than on state. The Borg design nonpattern makes all instances share state instead, and Python makes this a snap.
In most cases in which you might think of using Singleton or Borg, you don’t really need either of them. Simply define a Python module, with functions and module-global variables, instead of defining a class, with methods and per-instance attributes. You need to use a class only if you must be able to inherit from it or if you need to take advantage of the class’s ability to define special methods (for this issue, see Recipe 5.16)
The Singleton design pattern is all about ensuring that just one instance of a certain class is ever created. In my experience, it is usually not a good solution to the problems it tries to solve, displaying different kinds of problems in different object models. Typically, what we really want is to let as many instances be created as necessary, but all with shared state. Who cares about identity? It’s state (and behavior) we care about. This alternate pattern to solve roughly the same problems has also been called Monostate. Incidentally, I like to call Singleton “Highlander”, since there can be only one.
In Python, you can implement Monostate in many ways, but the Borg
design nonpattern is often best. Simplicity is its greatest strength.
Since the _ _dict_ _
of any instance can be
re-bound, Borg
rebinds it in its _ _init_ _
to a class-attribute dictionary. Now, any reference or
binding of an instance attribute will actually affect all instances
equally. I thank David Ascher for suggesting the appropriate name
“Borg” for this nonpattern.
It’s a nonpattern because it had no known uses at
the time of publication: two or more known uses are part of the
prerequisites for being a design pattern. See the detailed discussion
at http://www.aleax.it/Python/5ep.html.
The _ _getattr_ _
and _ _setattr_ _
special methods are not involved. You can define them
independently for whatever other purposes you want, or leave them
undefined. There is no problem either way, since Python does not call
_ _setattr_ _
for the rebinding of _ _dict_ _
itself.
Also, if you want instances of your class to share state among
themselves but not with instances of other subclasses of
Borg
, make sure that your class has the statement:
_shared_state = {}
in class scope so that it doesn’t inherit the
_shared_state
attribute from
Borg
but rather overrides it.
It’s to enable this usage that
Borg
’s _ _init_ _
method refers to self._shared_state
instead of Borg._shared_state
.
Borg also works for the new-style classes of Python 2.2, as long as
they don’t choose to keep state somewhere other than
in the instance’s _ _dict_ _
. For
example, Borg cannot support the _ _slots_ _
optimization. However, Borg saves as least as much memory per
instance as _ _slots_ _
(the few tens of bytes
normally taken up by the instance’s nonshared
_ _dict_ _
), so this isn’t really
an issue. To Borg-ize a new-style class that inherits from
list
or dict
and keeps state in
the items of its built-in base class, you can use automatic
delegation, as shown in Recipe 5.9. This
technique involves wrapping a classic class around the new-style one
and Borg-izing the classic class; I call this idea DeleBorg on
http://www.aleax.it/Python/5ep.html.
Calling this recipe a Singleton would be as silly as calling an arcade an umbrella. Both may serve similar purposes (letting you walk in the rain without getting wet)—or solve similar forces, in design patterns parlance—but since they do so in utterly different ways, they’re not instances of the same pattern. If anything (as already mentioned), Borg has similarities to the Monostate alternative design pattern to Singleton. (But Monostate is a design pattern, while Borg is not. And a Python Monostate can exist perfectly well without being a Borg.)
For reasons mysterious to me, people often conflate issues germane to Borg and Highlander with others that are really independent, such as access control and, particularly, access from multiple threads. If you need to control access to an object, that need is exactly the same whether there is 1 instance of that object’s class or 23, and whether those multiple instances share state or not. A fruitful approach to problem-solving is known as “divide and conquer,” or making problems easier by splitting their different aspects apart. Making problems harder by joining several aspects together must be an example of an approach known as “unite and suffer!”
Recipe 5.9 and Recipe 5.22; the article “Five Easy Pieces: Simple Python Non-Patterns” by Alex Martelli (http://www.aleax.it/5ep.html).
Get Python Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.