
If you’re no longer a newbie to Python, one of the most important Programming techniques called "Design Pattern" is a must-known one. Design patterns are usually best practices and the most effective approaches to solve some typical problems and requirements in software development.
In this article, I will introduce one of the most popular design patterns – Singleton. It is a special way of defining a class that ensures that it can only have one instance at a time.
I’ll start with how to write a singleton class in a standard way. Then, the main focus of this article is to show you some typical and practical examples of code. Therefore, we will know when to use it and what are the best practices of this design pattern.
1. How to Write A Basic Singleton

Before writing a singleton class, let’s have a look at a normal class. So, later on, we can compare it with the singleton.
1.1 A Normal Class
For a normal class, it can be instantiated as many times as we need to, and the instances are independent of each other.
Python">class Normal:
pass
normal1 = Normal()
normal2 = Normal()
print(normal1 is normal2)

Therefore, the normal1
and normal2
instances are different. We can also verify the memory address, they must not be the same.
print(normal1)
print(normal2)

The purpose of the Singleton Design Pattern is to make sure that no matter how many times we instantiate a class in anywhere the running program, we guarantee to have one and only one instance physically.
That means if there is no instance of this class yet, we need to create one. If there is already one in the runtime, we get this instance and reuse it. Therefore, for a singleton class, it will never have more than 1 instance at one time.
1.2 A Singleton Class

The most typical and native way of writing a singleton class in Python will be using the __new__()
function. Below is the simplest example of a singleton class.
class Singleton:
_instance = None
def __new__(cls):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
def some_functions(self):
pass
Why does the "instance" variable start with an underscore ""?
The _instance
is a variable to hold the existing instance of the singleton class. The basic idea is that, if _instance
is None
, we will need to create a new instance, otherwise, we should not, and the _instance
will be returned. So, it guarantees there will be at most one instance for this class. The underscore _
is just a naming convention in Python. Usually, we use it to indicate that this variable should not be accessed directly from outside the class. There is nothing magic, but good manners to keep the standard.
What is the "new()" method?
The __new__()
method is a static method in Python Class that will be called when an instance is about to be created from the current class. BTW, It is executed even before the __init__()
method. Therefore, we will need to check if an instance is already existing in the _instance
.
What is the "cls" argument in the "__new__()"
method?
Lastly, the cls
stands for "class". It provides a reference to the class itself. When the __new__()
method is called, it needs to know which class instance it should create. The logic is quite similar we use self
argument in the __init__(self)
function.
Now, let’s verify this singleton class.
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2)

It shows that even though we instantiated the Singleton
class twice, the two instances are actually the same one. We can also check the memory address, they are exactly the same.

2. When We Need Singleton

The reasons for using the singleton design pattern are obvious. That is, we don’t want this class to have multiple instances. This could be for the following scenarios.
- Resource Management
- Global Accessible Object
- Service Provider
2.1 A Resource Management Example – Database Connection
One of the most typical use cases of the singleton design pattern is the Database Connection. In one running program, it is unlikely we have to connect to multiple databases.
Therefore, writing a singleton class to wrap the Database Connection and make sure it can be used anywhere in the program is a good idea. It ensures that we don’t open too many connections, saving the system resources, mitigating the concurrency problems, and so on.
Here is a typical singleton class for SQLite3 connection. BTW, You can try the code without preparing anything, because Python has SQLite3 Database built-in (click the link if you don’t know this).
import sqlite3
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(DatabaseConnection, cls).__new__(cls)
# Connect to the database
cls._instance.connection = sqlite3.connect('example.db')
return cls._instance
def query(self, query):
cursor = self.connection.cursor()
cursor.execute(query)
return cursor.fetchall()
def close(self):
self.connection.close()
There is nothing fancy in the above code. It is based on the previous example, with two more methods. The query()
method is taking a query and returning the results, while the close()
method is just for closing the connection.
Let’s create our first instance of the DB Connection, and create a simple table called TEST_TABLE
with a record inserted into it.
db_connection1 = DatabaseConnection()
# Create a table
db_connection1.query("CREATE TABLE TEST_TABLE (id int, name string)")
db_connection1.query("INSERT INTO TEST_TABLE VALUES (1, 'Chris')")

The method returned an empty array because neither the queries returns anything. As long as there is no error, it means everything should be good.
Now, let’s create another DB connection, and they should be the same one because the DatabaseConnection
is a singleton class.
db_connection2 = DatabaseConnection()
print(db_connection1 is db_connection2)

Let’s try to use the 2nd DB connection to query the table we’ve just created, it should work.
results = db_connection2.query("SELECT * FROM TEST_TABLE;")
print(results)

See, it returns the row we have inserted. Now let’s try to close the connection for db_connection1
.
db_connection1.close()
It returns nothing, but the connection should have been closed already and the resources were released. Based on the behaviour of the singleton design pattern, even though we closed the db_connection1
, but the db_connection2
should also be closed because they are literally the same instance. We can verify this.
db_connection2.query("SELECT 1")

The error message tells us it has been closed. It works well as expected!
2.2 A Global Accessible Object Example – Feature Toggle Manager
One of the other common scenarios in which we need a singleton class is the globally accessible object. Sometimes, it can also be used for persisting configurations that can be set and accessed anywhere in the program.
For example, we can define a FeatureToggleManager
and get the singleton instance from any view controllers and access if "dark mode" is enabled. The class is defined as follows.
class FeatureToggleManager:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(FeatureToggleManager, cls).__new__(cls)
# Initialize with default feature enabling states
cls._instance.features = {
'new_ui': False,
'beta_feature': False,
'dark_mode': True
}
return cls._instance
def enable_feature(self, feature_name):
self.features[feature_name] = True
def disable_feature(self, feature_name):
self.features[feature_name] = False
def is_feature_enabled(self, feature_name):
return self.features.get(feature_name, False)
Then, we can enable the dark mode anywhere in the program.
feature_manager1 = FeatureToggleManager()
feature_manager1.enable_feature('dark_mode')
# Check if dark mode is enabled
feature_manager1.is_feature_enabled('dark_mode')

Suppose we are in another view controller of our app, we can easily get the singleton instance and check the feature state as well.
feature_manager2 = FeatureToggleManager()
feature_manager2.is_feature_enabled('dark_mode')
# Check if the two instances are the same one
print(feature_manager2 is feature_manager1)

2.3 Service Provider – Network Manager
The last practical example I want to show is the Network Manager. If our application needs to send lots of requests to an API endpoint, rather than calling request.get()
or other methods every time, we may want to encapsulate our REST API endpoints into different methods as follows.
import requests
class NetworkManager:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(NetworkManager, cls).__new__(cls)
cls._instance.base_url = "https://api.example.com"
return cls._instance
def list_items(self, category_id):
endpoint = f"categories/{category_id}/items"
response = requests.get(f"{self.base_url}/{endpoint}")
return response.json()
def add_item(self, endpoint, item_data):
response = requests.post(f"{self.base_url}/{endpoint}", json=item_data)
return response.json()
def update_item(self, endpoint, item_id, item_data):
full_endpoint = f"{endpoint}/{item_id}"
response = requests.put(f"{self.base_url}/{full_endpoint}", json=item_data)
return response.json()
def delete_item(self, endpoint, item_id):
full_endpoint = f"{endpoint}/{item_id}"
response = requests.delete(f"{self.base_url}/{full_endpoint}")
return response.json()
In the above example, we use the four methods that use different RESTful verbs typically for different purposes. For example, when we want to list all items in a category, we can do the following.
network_manager = NetworkManager()
items_in_category = network_manager.list_items(category_id="123")
print("Items in Category:", items_in_category)
Of course, don’t forget why we want to write our NetworkManager
class as singleton. That’s because, we can safely access the same instance everywhere without repeating the definitions, configurations, states and memory resources in our application.
Summary

In this article, I have introduced one of the most important design patterns in software engineering and how to implement it in Python. Some common questions regarding the code, especially regarding the __new()__
methods were also answered.
I believe the major contribution of this article is the practical examples of the usage of the singleton design pattern. Three different but frequent real-world examples were provided. I hope this helps you understand not only how to write a singleton class in Python, but also when to use it!
Unless otherwise noted all images are by the author