×

Singleton Design Pattern with Python

Singleton Design Patterns Python Feature

 The singleton design pattern is a common creational design pattern that suggests the instantiation of a class to one “single” instance. Provided the object (instance) has a global access point. SDP is considered as a way of defining a class.

Singleton Design Patterns

Singleton design pattern is preferred to used where only a single instance of a class is necessary to control the action throughout the execution. A singleton class shouldn’t have multiple instances in any case or at any cost.

Singleton classes are used where it makes sense to have one object in the entire system because initializer(instantiation) calls become expensive if instance represents any resource. For example, instance of the classes that are performing actions like creating Driver objects, Caching and keeping thread pool, logging and establishing Database connections etc…

  • The creation of a single instance also helps to ensure that some aspects of our programs cannot be overridden by other classes resulting in unsafe or inefficient code. 
  • The control of object creation is achieved by implementing a creation method that saves the created object in a static field.

There should be a method within the interface(i.e. interface having one instance), whose duty will be to provide the global access of the Single Instance, serving as Instance Allocator.

For reference, let’s see how to achieve a single instantiation of an object. And, understand the whole procedure parts by part, first we defined the class variable __instance__, that will hold the single object to be instantiated.

__instance__ = None

Now as we know when we do instantiation, a call to the constructor is made. Here, after a call, the constructor will first check if there is an existing instance or not, if yes raise an error, else create the instance.

def __init__(self):
       """ Constructor """
       if Singleton.__instance__ is None:
           Singleton.__instance__ = self
       else:
           raise Exception("Attempt to create another Instance")

Then there is get_instance() method, whose duty will be to check whether is there any existing instance or not, if yes it should return the instance, else it should create the new instance. The get_instance() method is working as an Instance allocator. Since get_instance() is not specific to an instance, hence kept static.

@staticmethod
   def get_instance():
       """ Static method to get the instance."""
       if not Singleton.__instance__:
           Singleton()
       return Singleton.__instance__

The full code will look like this:

class Singleton:
   __instance__ = None

   def __init__(self):
       """ Constructor """
       if Singleton.__instance__ is None:
           Singleton.__instance__ = self
       else:
           raise Exception("Attempt to create another Instance")

   @staticmethod
   def get_instance():
       """ Static method to get the instance."""
       if not Singleton.__instance__:
           Singleton()
       return Singleton.__instance__

However, we have configured the __init__ function in such a way that, it will raise an error if the call is made to create a second instance. But what if we prefer to return the first instance itself, on the second call. We can use the __new__ method.

class Singleton:
    __instance__ = None

    def __new__(cls):
        # If there is no instance create one
        if cls.__instance__ is None:
           cls.__instance__ = super(Singleton, cls).__new__(cls) 

        # If another call is made, return the first instance 
        return cls.__instance__

Here, __new__ has an eye on instance creation as well it is working as an Instance allocator. The line that may seem confusing is

cls.__instance__ = super(Singleton, cls).__new__(cls)

Let’s understand it step by step, Super method is creating a proxy(temporary) object of our Singleton class:

super(Singleton, cls)

That proxy object makes a call to __new__ method with cls as a parameter, and here cls represents Singleton. That creates the actual object, and we store it in our __instance__ variable.

super(Singleton, cls).__new__(cls)

These are some implementations on the Singleton Design Pattern, which restricts the instantiation of a class to one object. Mostly Used to limit concurrent access to a shared resource.

But, since there will be only one instance to communicate with the rest of the entities, leading to the development of some hidden dependencies (i.e. tight-coupling) between modules(entities) in certain implementations, making it difficult to track and test, hence keep testing in mind while obeying the Singleton design pattern.

Pros and Cons of the Singleton Design Pattern

Pros

  •  Since there is only one instance of our class it reduces the risk of unexpected behaviour in our program.
  • Creation of the object(instance) is controlled by a single class, this offers flexibility since changes only need to be made to one class and object.

Cons

  • Singleton pattern violates the Single Responsibility Principle since the class may have to handle more than one responsibility at a given time.
  • May require several Testings.