Skip to content
Related Articles

Related Articles

Singleton Pattern in Python – A Complete Guide

View Discussion
Improve Article
Save Article
Like Article
  • Difficulty Level : Hard
  • Last Updated : 27 Aug, 2021

A Singleton pattern in python is a design pattern that allows you to create just one instance of a class, throughout the lifetime of a program. Using a singleton pattern has many benefits. A few of them are:

  • To limit concurrent access to a shared resource.
  • To create a global point of access for a resource.
  • To create just one instance of a class, throughout the lifetime of a program.

Different ways to implement a Singleton:

A singleton pattern can be implemented in three different ways. They are as follows:

  • Module-level Singleton
  • Classic Singleton
  • Borg Singleton

Module-level Singleton:

All modules are singleton, by definition.  Let’s create a simple module-level singleton where the data is shared among other modules. Here we will create three python files –,, and – in which the other sample modules share a variable from 

shared_variable = "Shared Variable"

import singleton
singleton.shared_variable += "(modified by samplemodule1)"
import singleton

Let’s look into the output.

Here, the value changed by samplemodule1 is also reflected in samplemodule2.

Classic Singleton:

Classic Singleton creates an instance only if there is no instance created so far; otherwise, it will return the instance that is already created. Let’s take a look at the below code.


class SingletonClass(object):
  def __new__(cls):
    if not hasattr(cls, 'instance'):
      cls.instance = super(SingletonClass, cls).__new__(cls)
    return cls.instance
singleton = SingletonClass()
new_singleton = SingletonClass()
print(singleton is new_singleton)
singleton.singl_variable = "Singleton Variable"


Singleton Variable

Here, in the __new__ method, we will check whether an instance is created or not. If created, it will return the instance; otherwise, it will create a new instance. You can notice that singleton and new_singleton return the same instance and have the same variable.

Let’s check what happens when we subclass a singleton class. 


class SingletonClass(object):
  def __new__(cls):
    if not hasattr(cls, 'instance'):
      cls.instance = super(SingletonClass, cls).__new__(cls)
    return cls.instance
class SingletonChild(SingletonClass):
singleton = SingletonClass() 
child = SingletonChild()
print(child is singleton)
singleton.singl_variable = "Singleton Variable"



Singleton Variable

Here, you can see that SingletonChild has the same instance of SingletonClass and also shares the same state. But there are scenarios, where we need a different instance, but should share the same state. This state sharing can be achieved using Borg singleton.

Borg Singleton: 

Borg singleton is a design pattern in Python that allows state sharing for different instances. Let’s look into the following code.


class BorgSingleton(object):
  _shared_borg_state = {}
  def __new__(cls, *args, **kwargs):
    obj = super(BorgSingleton, cls).__new__(cls, *args, **kwargs)
    obj.__dict__ = cls._shared_borg_state
    return obj
borg = BorgSingleton()
borg.shared_variable = "Shared Variable"
class ChildBorg(BorgSingleton):
childBorg = ChildBorg()
print(childBorg is borg)


Shared Variable

Along with the new instance creation process, a shared state is also defined in the __new__ method. Here the shared state is retained using the shared_borg_state attribute and it is stored in the __dict__ dictionary of each instance.

If you want a different state, then you can reset the  shared_borg_state attribute. Let’s see how to reset a shared state.


class BorgSingleton(object):
  _shared_borg_state = {}
  def __new__(cls, *args, **kwargs):
    obj = super(BorgSingleton, cls).__new__(cls, *args, **kwargs)
    obj.__dict__ = cls._shared_borg_state
    return obj
borg = BorgSingleton()
borg.shared_variable = "Shared Variable"
class NewChildBorg(BorgSingleton):
    _shared_borg_state = {}
newChildBorg = NewChildBorg()

Here, we have reset the shared state and tried to access the shared_variable. Let’s see the error.

Traceback (most recent call last):
  File "/home/", line 16, in <module>
AttributeError: 'NewChildBorg' object has no attribute 'shared_variable'

Use cases of a Singleton:

Let’s list a few of the use cases of a singleton class. They are as follows:

  • Managing a database connection
  • Global point access to writing log messages
  • File Manager
  • Print spooler

Create a Web Crawler using Classic Singleton:

Let’s create a webcrawler that uses the benefit of a classic singleton. In this practical example, the crawler scans a webpage, fetch the links associated with the same website, and download all the images in it. Here, we have two main classes and two main functions.

  • CrawlerSingleton: This class acts a classic singleton
  • ParallelDownloader: This class provides thread functionality to download images
  • navigate_site: This function crawls the website and fetches the links that belong to the same website. And, finally, it arranges the link to download images.
  • download_images: This function crawls the page link and downloads the images.

Apart from the above classes and functions, we use two sets of libraries to parse the web page – BeautifulSoap and HTTP Client.

Have a look at the below code. 

Note: Execute the code in your local machine


import httplib2
import os
import re
import threading
import urllib
import urllib.request
from urllib.parse import urlparse, urljoin
from bs4 import BeautifulSoup
class CrawlerSingleton(object):
    def __new__(cls):
        """ creates a singleton object, if it is not created,
        or else returns the previous singleton object"""
        if not hasattr(cls, 'instance'):
            cls.instance = super(CrawlerSingleton, cls).__new__(cls)
        return cls.instance
def navigate_site(max_links = 5):
    """ navigate the website using BFS algorithm, find links and
        arrange them for downloading images """
    # singleton instance
    parser_crawlersingleton = CrawlerSingleton()
    # During the initial stage, url_queue has the main_url.
    # Upon parsing the main_url page, new links that belong to the
    # same website is added to the url_queue until
    # it equals to max _links.
    while parser_crawlersingleton.url_queue:
        # checks whether it reached the max. link
        if len(parser_crawlersingleton.visited_url) == max_links:
        # pop the url from the queue
        url = parser_crawlersingleton.url_queue.pop()
        # connect to the web page
        http = httplib2.Http()
            status, response = http.request(url)
        except Exception:
        # add the link to download the images
        # crawl the web page and fetch the links within
        # the main page
        bs = BeautifulSoup(response, "html.parser")
        for link in BeautifulSoup.findAll(bs, 'a'):
            link_url = link.get('href')
            if not link_url:
            # parse the fetched link
            parsed = urlparse(link_url)
            # skip the link, if it leads to an external page
            if parsed.netloc and parsed.netloc != parsed_url.netloc:
            scheme = parsed_url.scheme
            netloc = parsed.netloc or parsed_url.netloc
            path = parsed.path
            # construct a full url
            link_url = scheme +'://' +netloc + path
            # skip, if the link is already added
            if link_url in parser_crawlersingleton.visited_url:
            # Add the new link fetched,
            # so that the while loop continues with next iteration.
            parser_crawlersingleton.url_queue = [link_url] +\
class ParallelDownloader(threading.Thread):
    """ Download the images parallelly """
    def __init__(self, thread_id, name, counter):
        threading.Thread.__init__(self) = name
    def run(self):
        print('Starting thread',
        # function to download the images
        print('Finished thread',
def download_images(thread_name):
    # singleton instance
    singleton = CrawlerSingleton()
    # visited_url has a set of URLs.
    # Here we will fetch each URL and
    # download the images in it.
    while singleton.visited_url:
        # pop the url to download the images
        url = singleton.visited_url.pop()
        http = httplib2.Http()
        print(thread_name, 'Downloading images from', url)
            status, response = http.request(url)
        except Exception:
        # parse the web page to find all images
        bs = BeautifulSoup(response, "html.parser")
        # Find all <img> tags
        images = BeautifulSoup.findAll(bs, 'img')
        for image in images:
            src = image.get('src')
            src = urljoin(url, src)
            basename = os.path.basename(src)
            print('basename:', basename)
            if basename != '':
                if src not in singleton.image_downloaded:
                    print('Downloading', src)
                    # Download the images to local system
                    urllib.request.urlretrieve(src, os.path.join('images', basename))
                    print(thread_name, 'finished downloading images from', url)
def main():
    # singleton instance
    crwSingltn = CrawlerSingleton()
    # adding the url to the queue for parsing
    crwSingltn.url_queue = [main_url]
    # initializing a set to store all visited URLs
    # for downloading images.
    crwSingltn.visited_url = set()
    # initializing a set to store path of the downloaded images
    crwSingltn.image_downloaded = set()
    # invoking the method to crawl the website
    ## create images directory if not exists
    if not os.path.exists('images'):
    thread1 = ParallelDownloader(1, "Thread-1", 1)
    thread2 = ParallelDownloader(2, "Thread-2", 2)
    # Start new threads
if __name__ == "__main__":
    main_url = ("")
    parsed_url = urlparse(main_url)

Let’s look into the downloaded images and python shell output.

Downloaded Images

Python Shell Output


Singleton pattern is a design pattern in Python that restricts the instantiation of a class to one object. It can limit concurrent access to a shared resource, and also it helps to create a global point of access for a resource. 

My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!