The Singleton Pattern in Python

Learn how to implement the singleton pattern in Python and why module-level variables often serve the same purpose more naturally.

7 min read

The singleton pattern ensures a class has exactly one instance and provides a global point of access to it. In languages like Java, implementing a singleton requires private constructors, static methods, and thread-safety considerations. Python's module system makes the pattern much simpler, and in many cases you do not need a class at all.

This article covers the Pythonic approaches to singletons, from the module-level pattern you should use most of the time to the class-based approach for when you need more control. It builds on the module design principles from designing reusable Python modules.

Modules are singletons

The most Pythonic singleton is a module. When Python imports a module, it executes it once and caches the result in sys.modules. Every subsequent import in any file retrieves the same module object. This is exactly what a singleton provides, without any special code.

A configuration manager using a module needs no class at all. Module-level variables hold the shared state:

pythonpython
# config.py
_settings = {}
_loaded = False
 
 
def load(path):
    global _settings, _loaded
    with open(path) as fh:
        _settings = json.load(fh)
    _loaded = True
 
 
def get(key, default=None):
    return _settings.get(key, default)
 
 
def is_loaded():
    return _loaded

Every file that needs configuration imports the module. All importers share the same _settings dictionary. If one part of the application calls config.load(), every other part sees the loaded data immediately.

The class-based singleton with new

When you need a class with inheritance, lazy initialization, or a formal interface that tools can check, use a class with __new__ to enforce single instance creation:

pythonpython
class DatabasePool:
    _instance = None
 
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._initialized = False
        return cls._instance
 
    def __init__(self, connection_string=None):
        if self._initialized:
            return
        self.connection_string = connection_string
        self._connections = []
        self._initialized = True
 
    def get_connection(self):
        conn = self._create_connection()
        self._connections.append(conn)
        return conn

The __new__ method ensures only one instance exists. The __init__ method uses a guard to avoid reinitializing the instance on subsequent calls. A caller writes pool = DatabasePool("postgresql://...") and always receives the same object.

This approach is useful when you need to subclass the singleton for testing. A test can create a MockDatabasePool that inherits from DatabasePool and overrides connection creation without affecting the production code. For a broader look at when the singleton fits alongside other patterns, see Common Design Patterns in Python.

Thread-safe singletons

The class-based approach above is not thread-safe. Two threads calling DatabasePool() simultaneously could both see _instance is None and create two instances. Add a lock to prevent this:

pythonpython
import threading
 
class DatabasePool:
    _instance = None
    _lock = threading.Lock()
 
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                    cls._instance._initialized = False
        return cls._instance

The double-checked locking pattern acquires the lock only when the instance might need creation. After creation, subsequent calls skip the lock entirely.

For most applications, the module-level approach avoids threading concerns entirely because module imports are thread-safe in Python. The import system handles the locking for you.

When modules beat classes

A module is the right choice when your singleton manages shared state without complex behavior. Configuration, caches, connection pools, and loggers all fit this pattern. The syntax is familiar, the import system handles thread safety, and there is no boilerplate.

A class is the right choice when you need inheritance for testing, when the singleton must conform to a Protocol or ABC for type checking, or when lazy initialization matters because creating the instance is expensive.

If you are unsure, start with a module. It is trivial to upgrade to a class later if requirements change. Going the other direction, from a class with new tricks back to a simple module, is harder because callers have already coupled to the class interface.

Rune AI

Rune AI

Key Insights

  • Python modules are singletons by default: imported once, shared by all importers.
  • Use module-level variables for configuration, caches, and shared state.
  • A class-based singleton with new works when you need inheritance or lazy init.
  • Avoid over-engineering; a module is often the simplest and most Pythonic solution.
RunePowered by Rune AI

Frequently Asked Questions

Does Python have a built-in singleton?

No, Python has no built-in Singleton keyword or decorator in the standard library. But Python modules are effectively singletons: a module is imported once, and all importers share the same module object and its variables.

When should I use a singleton in Python?

Use a singleton when you need exactly one instance of a class that manages shared state, such as a configuration manager, a database connection pool, a logger, or a cache. For simple cases, a module with global variables is more Pythonic than a class-based singleton.

Conclusion

Python modules are the most natural singleton. Before writing a class with new tricks or metaclasses, ask whether a module with a few functions and module-level variables solves the same problem with less code. Reach for a class-based singleton only when you need inheritance, lazy initialization, or a formal interface.