Why is the Borg pattern better than the Singleton pattern in Python
Why is the Borg pattern better than the Singleton pattern in Python
The real reason that borg is different comes down to subclassing.
If you subclass a borg, the subclass objects have the same state as their parents classes objects, unless you explicitly override the shared state in that subclass. Each subclass of the singleton pattern has its own state and therefore will produce different objects.
Also in the singleton pattern the objects are actually the same, not just the state (even though the state is the only thing that really matters).
In python if you want a unique object that you can access from anywhere just create a class Unique
that only contains static attributes, @staticmethod
s, and @classmethod
s; you could call it the Unique Pattern. Here I implement and compare the 3 patterns:
Unique
#Unique Pattern
class Unique:
#Define some static variables here
x = 1
@classmethod
def init(cls):
#Define any computation performed when assigning to a new object
return cls
Singleton
#Singleton Pattern
class Singleton:
__single = None
def __init__(self):
if not Singleton.__single:
#Your definitions here
self.x = 1
else:
raise RuntimeError(A Singleton already exists)
@classmethod
def getInstance(cls):
if not cls.__single:
cls.__single = Singleton()
return cls.__single
Borg
#Borg Pattern
class Borg:
__monostate = None
def __init__(self):
if not Borg.__monostate:
Borg.__monostate = self.__dict__
#Your definitions here
self.x = 1
else:
self.__dict__ = Borg.__monostate
Test
#SINGLETON
print nSINGLETONn
A = Singleton.getInstance()
B = Singleton.getInstance()
print At first B.x = {} and A.x = {}.format(B.x,A.x)
A.x = 2
print After A.x = 2
print Now both B.x = {} and A.x = {}n.format(B.x,A.x)
print Are A and B the same object? Answer: {}.format(id(A)==id(B))
#BORG
print nBORGn
A = Borg()
B = Borg()
print At first B.x = {} and A.x = {}.format(B.x,A.x)
A.x = 2
print After A.x = 2
print Now both B.x = {} and A.x = {}n.format(B.x,A.x)
print Are A and B the same object? Answer: {}.format(id(A)==id(B))
#UNIQUE
print nUNIQUEn
A = Unique.init()
B = Unique.init()
print At first B.x = {} and A.x = {}.format(B.x,A.x)
A.x = 2
print After A.x = 2
print Now both B.x = {} and A.x = {}n.format(B.x,A.x)
print Are A and B the same object? Answer: {}.format(id(A)==id(B))
Output:
SINGLETON
At first B.x = 1 and A.x = 1 After A.x = 2 Now both B.x = 2 and A.x = 2 Are A and B the same object? Answer: True BORG At first B.x = 1 and A.x = 1 After A.x = 2 Now both B.x = 2 and A.x = 2 Are A and B the same object? Answer: False UNIQUE At first B.x = 1 and A.x = 1 After A.x = 2 Now both B.x = 2 and A.x = 2 Are A and B the same object? Answer: True
In my opinion, Unique implementation is the easiest, then Borg and finally Singleton with an ugly number of two functions needed for its definition.
Why is the Borg pattern better than the Singleton pattern in Python
It is not. What is generally not recommended is a pattern like this in python:
class Singleton(object):
_instance = None
def __init__(self, ...):
...
@classmethod
def instance(cls):
if cls._instance is None:
cls._instance = cls(...)
return cls._instance
where you use a class method to get the instance instead of the constructor. Pythons metaprogramming allows much better methods, e.g. the one on Wikipedia:
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
print MyClass()
print MyClass()