How do you implement a singleton in Python, and what are the tradeoffs of different approaches?

6 minintermediateoopsingletondesign-patterns

Quick Answer

Common approaches: override `__new__` to always return the same instance, use a module (modules are already singletons — Python caches them in `sys.modules`), or use a metaclass that caches instances per class. The module-level approach is usually the simplest and most Pythonic; `__new__`-based and metaclass-based singletons add complexity that's rarely worth it outside of specific framework needs, and singletons in general are often better replaced by dependency injection for testability.

Detailed Answer

Approach 1: a module (the idiomatic Python singleton)

# config.py
_settings = {}

def get_settings():
    if not _settings:
        _settings.update(load_from_disk())
    return _settings

Modules are imported once and cached in sys.modules, so any module-level state is naturally a singleton — every importer sees the same object. This is the simplest, most idiomatic option and is exactly what most "singleton" needs in Python actually call for.

Approach 2: overriding __new__

class Singleton:
    _instance = None

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

a = Singleton()
b = Singleton()
a is b   # True

__new__ runs before __init__ and is responsible for actually creating the instance — by returning a cached instance instead of creating a new one, every call to Singleton() returns the same object. Watch out: __init__ still runs every time Singleton() is called (even on the cached instance), so you typically need to guard re-initialization too.

Approach 3: a metaclass

class SingletonMeta(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class Database(metaclass=SingletonMeta):
    pass

This centralizes the singleton logic in one reusable metaclass rather than duplicating __new__ in every class that needs it — useful if you have many singleton classes, at the cost of adding metaclass complexity.

The tradeoff nobody skips: testability

Singletons introduce global mutable state, which makes unit tests harder to isolate (tests can leak state into each other through the shared instance) and makes dependency substitution awkward (you can't easily swap in a fake Database for a test without monkeypatching the singleton).

The more commonly recommended alternative in modern Python code is dependency injection: construct the shared object once (e.g., in main() or an app factory) and pass it explicitly to whatever needs it, rather than having classes reach out and grab a global singleton themselves. This keeps the "there's only one" property where it's genuinely needed (one process, one instance) while keeping tests able to substitute a fresh instance per test.

Interview-ready summary: The simplest, most Pythonic singleton is just a module-level object (modules are already cached singletons); __new__- or metaclass-based singletons work but add complexity. In practice, prefer constructing the shared object once and passing it explicitly (dependency injection) over a true singleton, since global state makes testing harder.

Related Resources