Welcome, guest | Sign In | My Account | Store | Cart

The Singleton design pattern (DP) has a catchy name, but the wrong focus -- on identity rather than on state. The Borg design pattern has all instances share state instead, and Python makes it, literally, a snap.

Python, 7 lines
1
2
3
4
5
6
7
class Borg:
    __shared_state = {}
    
    def __new__(cls, *args, **kwargs):
        instance = super().__new__(cls, *args, **kwargs)
        instance.__dict__ = cls.__shared_state
        return instance

The 'Singleton' DP is all about ensuring that just one instance of a certain class is ever created. It has a catchy name and is thus enormously popular, but it's NOT a good idea -- it displays different sorts of problems in different object-models. What we should really WANT, typically, 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!

You can ensure this in many ways in Python, but the Borg design pattern is almost always best. Since the self.__dict__ of any instance can be re-bound, just re-bind it in __init__ to a class-attribute dictionary -- that's all! Now any reference or binding of an instance attribute will actually affect all instances equally -- "we all are one", and all that jazz. Thanks to David Ascher for suggesting the very appropriate name "Borg" for this DP.

Note that __getattr__ and __setattr__ are not involved -- they can be defined independently for whatever other purposes, or left undefined (and __setattr__, if defined, is NOT called for the rebinding of __dict__ itself). This only works with 'classic classes' (all classes in Python 2.1 and earlier, those that don't inherit from built-in types in 2.2 and later), whose instances keep all their per-instance state via self.__dict__ -- 2.2/+ classes with self.__slots__ do not support this idiom quite as smoothly (you can use getters/setters for such advanced-classes to deal with this issue, if you wish, but sticking to 'classic classes' for these needs may be simplest).

3 comments

s_h_a_i_o 10 years, 2 months ago  # | flag

Very nice recipe (although the 2.0 version is much shorter).

I have 2 questions about it please:

*/ Why rebinding of self.__dict__ would not call self.__setattr__ ?

*/ I would like to inherit from Borg, while adding non-shared attributes in the derived class.

  • Is it relevant with the Borg pattern ?
  • Is it possible ? (maybe with a way to specify that only some attributes are shared, while others are not - but I'm afraid using 2 dicts would break the beauty of this recipe)

Thanks

Jonathan Blakes 10 years, 2 months ago  # | flag

A module can also act a singleton, without any code!

Anler Hernández Peral (author) 10 years, 2 months ago  # | flag

@s_h_a_i_o yes, calling self.__dict__ would call self.__setattr__ ... but, since is not defined, it works as expected. If you want a class, that lets you have, shared and private attributes, its even more simple to accomplish, take for example:

class Borg:

    __shared_state = {}

    def getshared(self, name, default=None):
        return self.__shared_state.get(name, default)

    def setshared(self, name, value):
        self.__shared_state[name] = value

Here, setting attributes directly, will be added as private for each instance. if you need some shared attribute use getshared/setshared instead

@Jonathan yes, you're completely right about it, but I think it's usefull(in order to learn) to play with the language a little bit, although, there are times that maybe this pattern would be more appropiate if you want for example, keep a shared object thread-safe