Detailed Explanation of the Singleton Pattern in Python

Background

Have you heard of the Singleton Pattern in Python? I encountered it while reading someone else’s code and didn’t understand what that piece of code meant. Later, when I searched for information, I learned that the purpose of that code is to create a single instance. It was from that moment that I became aware of the term “Singleton”, which is a design pattern in Python. In simple terms, it means that there is only one instance of a class object in memory.

Singleton Pattern Code

class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance

My Environment

import sys

print('Python version:', sys.version.split('|')[0])
# Python version: 3.11.11

Detailed Explanation with a Large Model

When the instance object is created for the first time, the class attribute <span>_instance = None</span> is set, and then the program enters the if condition to execute the key statement:

cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
# cls._instance = super().__new__(cls, *args, **kwargs)

1. <span>super(Singleton, cls)</span>‘s Role

  • The super function: used to access methods from the parent class (base class), inheriting from the parent class and initializing it.
  • Parameter meanings:
    • <span>Singleton:</span><span> the current class</span>
    • <span>cls:</span><span> a reference to the current class (in class methods, cls represents the class itself)</span>

This syntax explicitly specifies that the search for the parent class starts from the <span>Singleton</span> class in the MRO (Method Resolution Order). In Python 3, it can be simplified to <span>super()</span>, but this syntax more clearly shows the inheritance relationship.

2. <span>.__new__(cls, *args, **kwargs)</span>

  • Calling the parent class’s <strong><span>new</span></strong> method: this is the key step in actually creating the object instance.
super(Singleton, cls).__new__(cls) → actually calls object.__new__(Singleton)

In CPython (the official implementation of Python), <span>object.__new__</span> is a low-level function implemented in C. Its core tasks are:

  1. Memory allocation: allocating appropriate memory space for the new object.
  2. Object initialization: setting up the basic structure of the object.
  3. Returning the raw object: returning an “empty”, uninitialized object instance.

<span>object.__new__</span> is a low-level implementation that does not trigger the Python-level <span>__new__</span> method call. When <span>object.__new__</span> executes:

  1. It directly operates on memory allocation without going through Python’s method lookup mechanism.
  2. It is a built-in C function of the interpreter, not a Python function.
  3. Its job is to create the raw object without checking or calling any <strong><span>new</span></strong> methods.

<span>object.__new__(Singleton)</span>‘s Working Principle:

  1. Memory allocation: allocating appropriate size memory for the Singleton instance.
  2. Object initialization: setting up the basic object header (type pointer, reference count, etc.).
  3. Returning the raw object: returning an “empty”, uninitialized object instance.

3. Return Assignment <span>cls._instance=</span> After step 2, the raw object will be assigned to <span>cls._instance</span>, which is actually the address/pointer of the class in memory. This way, the class attribute is no longer <span>None</span>, and if an instance is created again later, it will directly return the instance object created the first time.

Core Advantages of the Singleton Pattern

  1. Memory resource savings: there is only one object in memory, avoiding memory waste from creating duplicate instances.
  2. Reduced system overhead: the singleton can reside in memory for a long time, avoiding frequent creation and destruction of objects, thus reducing system overhead.
  3. Global access point: provides a global access point, allowing easy access to the unique instance in the application.
  4. Data synchronization control: with only one access point globally, better data synchronization control can be achieved, avoiding multiple occupancy.

Practical Application Scenarios of the Singleton Pattern

  1. Logger: applications usually only need one logger instance to avoid conflicts between multiple log files.
  2. Database connection pool: database connections are scarce resources, and using the singleton pattern can manage connections uniformly, avoiding resource waste.
  3. Configuration management: global configuration of applications usually only requires one instance to ensure consistency, such as initializing large models in memory/GPU only once to handle all user requests.
  4. Cache system: global caches need to be managed uniformly to avoid data inconsistency caused by multiple cache instances.

Related Historical Articles

  • Detailed Explanation of Python Collections: Unlocking Efficient Data Structures
  • Python Function Parameters: Lists as Default Values, a Hidden Trap!
  • Two Useful Decorator Functions in Python

The above are some issues I encountered in practice, shared for everyone’s reference and learning. Feel free to follow the WeChat public account: DataShare, where I will share valuable content from time to time.

Leave a Comment