Design Pattern: Singleton Pattern in Python

NOTES

In this article, we are discussing the implementation of the Singleton Pattern in Python.

Use the link below to check the details of the Singleton Pattern-

Implementation

Method #1: Simple Implementation (Not recommended, demo purpose only)

WARNING

This is not the recommended way to implement Singleton in Python. We are showing it for learning purposes only.

Use the method described in the next section(Method #2: Using Metaclass) when you want to implement the Singleton pattern in Python.

from typing import Optional


class Singleton:
    # Static variable to hold the singleton instance
    _singleton_instance: Optional["Singleton"] = None

    # Private constructor
    def __init__(self, some_val: str) -> None:
        if Singleton._singleton_instance is not None:
            raise Exception("This class is a singleton!")
        else:
            self.some_val = some_val

    @staticmethod
    def get_instance(some_val: str) -> "Singleton":
        # Check if the singleton instance is already created
        if Singleton._singleton_instance is None:
            Singleton._singleton_instance = Singleton(some_val)
        return Singleton._singleton_instance

    def print_details(self) -> None:
        print(f"some val: {self.some_val}")


# Usage:
if __name__ == '__main__':
    # Creating the first singleton instance
    singleton_instance = Singleton.get_instance("abc")
    singleton_instance.print_details()
    
    # Trying to create another instance
    another_instance = Singleton.get_instance("changed val")
    another_instance.print_details()
    
    # Uncommenting the following will raise an exception
    # new_instance = Singleton("new value")  # Error: This class is a singleton!
    
    # Checking if both instances are the same
    print(singleton_instance is another_instance)
Python

Output:

Following output will be generated-

some val: abc
some val: abc
True

Method #2: Using Metaclass (Recommended way in Python)

We have defined a metaclass named SingletonMeta. A metaclass is denoted as a “class of classes“, which defines how the classes would be created and managed.
We have defined a class-level dictionary named _instances, to store the generated class instances.
The __call__ method defines what happens when a class instance is generated by the metaclass(SingletonMeta).
In the __call__ method we are checking if an instance of the provided class already exists in our _instances dictionary. If an instance already exists then we return that instance, else we create a new instance, save it in the _instances dictionary and finally return that.
If an instance does not already exist then we are calling the parent “type” class’s __call__ method to create the instance.
Finally, we have created a Singleton class that uses the metaclass SingletonMeta.
class SingletonMeta(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            # Create the singleton instance if it doesn't exist
            instance = super().__call__(*args, **kwargs)
            cls._instances[cls] = instance
        return cls._instances[cls]


class Singleton(metaclass=SingletonMeta):
    def __init__(self, some_val: str) -> None:
        self.some_val = some_val

    def print_details(self) -> None:
        print(f"some val: {self.some_val}")


# Usage:
if __name__ == '__main__':
    # Creating the first singleton instance
    singleton_instance = Singleton("abc")
    singleton_instance.print_details()
    
    # Trying to create another instance
    another_instance = Singleton("changed val")
    another_instance.print_details()
    
    # Checking if both instances are the same
    print(singleton_instance is another_instance)
Python

NOTES

We could have used the _instances attribute to store a single object reference, instead of using a dictionary. But that would make it work for only one singleton class.

As we have used a dictionary, so we can use the same SingletonMeta class to implement the Singleton pattern for other classes. The _instances dictionary will store instances of all the all classes that are using SingletonMeta.

Output:

some val: abc
some val: abc
True

Examples

Example #1: Database Connection

DB Connection Singleton Class

Demo

Output

Following output is generated by the above code-

Creating new db connection instance

DB connection details for dbConnOne:
host:loclahost
port:1234
username:root
password:secret!pass


Using existing db connection instance

DB connection details for dbConnTwo:
host:loclahost
port:1234
username:root
password:secret!pass
Plaintext

Example #2: Setting

Setting Singleton Class

Demo

Use the method “getInstance” to create a new instance of the setting class.

Output

array(2) {
  ["file_base_path"]=>
  string(11) "/var/log/dd"
  ["app_port"]=>
  int(3000)
}

array(2) {
  ["file_base_path"]=>
  string(11) "/var/log/dd"
  ["app_port"]=>
  int(3000)
}
Plaintext

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Singleton pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.