A singleton is the simplest design pattern: a class with exactly one instance. Before using a classic implementation, ask whether the language already solves the problem, the question When a Pattern Dissolves poses for every pattern. For the singleton, the language already has an answer.
Python imports each module once and caches it in
sys.modules, as Modules and
Packages showed. Every import after the first
produces the same module object. A module is a singleton, and
everyone shares anything defined at module level, with one copy
for the whole interpreter. One interpreter, not one machine. A
process pool or an InterpreterPoolExecutor
gives each worker its own sys.modules, so each
builds its own copy and a write in one is invisible to the rest.
A singleton is single within the interpreter that holds it, and
every form in this chapter, the module included, has that
limit.
Put the state in a module:
# config.py
print("config body runs")
settings: dict[str, str] = {}# module_singleton.py
import config
import config as again
print(config is again, config.settings is again.settings)
#: config body runs
#: True TrueTwo import statements, one printed line. The
first one runs config.py top to bottom
and files the resulting module object in
sys.modules under the name config. The
second finds it there and skips the work, so the body runs once
and builds one settings dict. That is the
singleton: not a rule the class enforces, but a lookup the
import system performs.
Every import of settings, from anywhere, hands
back that same dict. Mutating it through one import
is visible through every other:
No class, no ceremony. For most singleton needs, a module solves the problem.
Mutation makes the sharing work. Rebinding is the mistake
that quietly ends it. from config import settings
gives your module its own name for the same dict
object named by config.settings. Mutating through
your name, settings["theme"] = "dark", changes that
shared object, so every module sees it. But
settings = {} in your module rebinds only your
module’s name, and the two modules silently diverge:
config.settings still holds the old dict, while
your code now talks to a private one. To replace the whole
value, go through the module: import config, then
config.settings = {...}. Mutate through any name.
Rebind only through the module.
Sharing also depends on the name. sys.modules
uses the module name as its key, and the file you launch runs
under the name __main__. If that file is config.py, a later
import config finds no cached entry, runs the body
again, and builds a second module object with its own
settings. Keep singleton state in a module you
import, not in the script you run.
The goal is that every construction returns the same object.
The simplest approach hides construction behind a cached
factory: functools.cache applied to a
constructor function, an ordinary function that builds
and returns an instance of a class. The constructor function
stands in for a direct call to the class constructor.
functools.cache (Caching)
memoizes a function. The first call with a given set of
arguments runs the function and stores the result. Every repeat
call with those arguments returns the stored result. A
constructor function with no arguments has only one possible
call, so caching it constructs the instance once and returns
that same object forever:
# singleton_cached_factory.py
from dataclasses import dataclass, field
from functools import cache
@dataclass
class Settings:
data: dict[str, str] = field(default_factory=dict)
@cache
def settings() -> Settings:
return Settings()
a = settings()
b = settings()
assert a is b
a.data["theme"] = "dark"
print(b)
#: Settings(data={'theme': 'dark'})Giving the constructor function a parameter breaks the
guarantee. functools.cache keys its cache on the
arguments, so each distinct argument value gets its own entry
and its own instance:
# singleton_cached_factory_footgun.py
from dataclasses import dataclass, field
from functools import cache
@dataclass
class Settings:
data: dict[str, str] = field(default_factory=dict)
@cache
def settings(env: str = "prod") -> Settings:
return Settings()
print(settings("prod") is settings("dev"))
#: FalseOne parameter turns “one singleton” into one singleton per argument value. Keep the constructor function’s signature empty, or accept that you built a cache, not a singleton.
Nothing stops a caller from writing Settings()
and getting a second instance. Naming the class
_Settings marks it internal and keeps it out of
from module import *, and that marking is as far as
Python goes. A second underscore adds no strength. The compiler
mangles
names only inside a class body, so at module level
__Settings is the plain name it looks like. Inside
a class body the compiler rewrites m.__Settings
into a lookup for _TheClass__Settings, and that
lookup fails.
This listing keeps the bare name for a reason that outlasts
the convention. settings() returns a
Settings, so the class already appears in the
module’s public signature. A caller who annotates the result
must write that name, and a type outsiders must name is not
private, whatever it starts with. _Settings fits a
type that never leaves the module.
Two stronger-looking moves fail the same way. Deleting the
name after building the instance leaves the class reachable:
type(settings()) hands it back. Defining the class
inside settings() leaves the module no name for it,
since @cache runs that body once and the class
lives in the function’s locals. type(settings())
still recovers the class.
Nesting costs the return annotation as well.
def settings() -> Settings still parses and
runs, because an annotation evaluates only when something reads
it, so a clean run proves nothing about the name. Whatever reads
the annotation searches the scope containing the function, while
the class lives in the function’s own locals. A type checker
reports an unresolved reference, and
inspect.get_annotations() raises a
NameError. The signature must name something
reachable, so nesting costs you either the annotation or a
separate Protocol to name in its place.
Privacy in Python is advice, not enforcement. An underscore
asks callers to stay out, and nothing makes them. Rethinking
Objects makes the same case about hidden data, where a
getter hands back a reference to the internals it should
protect. The reachable class is also useful when a test needs a
fresh, uncached Settings.
Three implementation notes:
A singleton holds shared state, and shared state leaks
between tests. The cached factory has an escape hatch the
classic forms lack: settings.cache_clear() discards
the instance, so each test can start fresh.
Every lazy singleton has a first-call race under threads.
Concurrent first calls can each run the constructor, and each
caller can end up holding a different object, with only one of
them staying in the cache. With a constructor slow enough to
widen that race, eight threads calling settings()
at once ran the constructor eight times and handed back eight
different objects. When threads can arrive before the singleton
exists, create it eagerly instead: call settings()
once at import time, or use the module form, which the import
system builds exactly once.
A lock is the
other fix for that race, but not in the obvious place. A
threading.Lock around the cached function’s body
changes nothing, because every thread has already missed the
cache before reaching the lock. They serialize, each still
builds an object, and the cache keeps whichever finished last.
The check must run inside the lock, as singleton_locked_settings.py
shows.
The race is easy to see with a wide enough window:
# singleton_cached_race.py
import time
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass, field
from functools import cache
@dataclass
class Settings:
data: dict[str, str] = field(default_factory=dict)
def __post_init__(self) -> None:
time.sleep(0.05) # Widen the first-call window
@cache
def settings() -> Settings:
return Settings()
with ThreadPoolExecutor(max_workers=8) as pool:
built = list(pool.map(lambda _: settings(), range(8)))
print(len({id(s) for s in built}) > 1)
#: TrueEight threads, more than one object. Every thread checks the cache before any of them has filled it, so each runs the constructor and hands its caller a different object. Only the last one to finish stays in the cache. The other seven are already in the hands of their callers.
@cache disappears below, because it no longer
makes the object single:
# singleton_locked_settings.py
import threading
import time
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass, field
from typing import Final
@dataclass
class Settings:
data: dict[str, str] = field(default_factory=dict)
def __post_init__(self) -> None:
time.sleep(0.05) # Widen the first-call window
_lock: Final[threading.Lock] = threading.Lock()
_instance: Settings | None = None
def settings() -> Settings:
global _instance
with _lock:
if _instance is None:
_instance = Settings()
return _instance
with ThreadPoolExecutor(max_workers=8) as pool:
built = list(pool.map(lambda _: settings(), range(8)))
print(len({id(s) for s in built}))
#: 1settings() declares global for
_instance and leaves _lock undeclared.
The mutate-versus-rebind distinction from A Module Is Already a
Singleton reappears here, from inside a function.
global governs rebinding, not use.
with _lock: reads the name, even though acquiring
and releasing changes that lock’s state, from unlocked to locked
and back. Changing an object is not rebinding a name.
_instance differs because the function assigns to
it. Python decides at compile time that a name a function
assigns anywhere is local everywhere in that function, so
without the global declaration,
if _instance is None reads an unassigned local and
raises an UnboundLocalError. Mutate through any
name. Declare only what you rebind.
One thread finds _instance empty and builds it.
The rest wait on the lock, and each finds _instance
already filled. Under the same eight-thread race, the cached
version produced eight objects. This version produces one, as
the printed count confirms. The sleep stands in for a
constructor that does real work, such as opening a file or a
connection. Without the sleep, the cached version showed no
duplicates across twenty trials, and that silence is the more
dangerous case. A window too narrow to reproduce is still a
window.
Every call now acquires the lock, including the thousands that arrive long after the object exists. That is the price of laziness under threads.
The classic escape is double-checked locking: test
_instance before taking the lock, take it when the
test finds the object missing, then test again inside. The
second test is the one note 3 requires. The first exists to skip
the lock once the object is there. Double-checked locking works,
but both checks must be exactly right, and a subtle mistake
reintroduces the race the lock exists to close. That is a bad
trade for saving one lock acquisition. Eager creation is a
better answer when you can build the object at import time:
# singleton_eager_factory.py
from dataclasses import dataclass, field
from functools import cache
@dataclass
class Settings:
data: dict[str, str] = field(default_factory=dict)
@cache
def settings() -> Settings:
return Settings()
settings() # Build it before any thread can race for it
print(settings() is settings())
#: TrueThe priming call is safe for the same reason the module form is: the import system runs a module body once, so the object exists before any thread can ask for it. The race needs laziness, and this listing gives it up on purpose.
If you need the class to hand back one instance from its own
constructor, override __new__(), as singleton_class_variable.py
does.
Modules and cached factories, primed at import time if threads are in play, should cover your singleton needs. The rest of this chapter is here for the techniques it demonstrates, not because you need these forms.
To address languages like C++ and Java, GoF Design Patterns builds the singleton with more apparatus. Each variation shown here does more work than the module or the cached factory above.
The first controls creation by delegating to a single instance of a private nested class. The rest reach it by other means: a class variable and a decorator, while Borg trades one object for one shared set of state.
The classic approach is lazy: it builds the inner
object on the first call, and that is why it needs the
None sentinel and the if guard.
# singleton_pattern.py
from dataclasses import dataclass, field
from typing import Any, ClassVar
class OnlyOne:
@dataclass
class __OnlyOne:
val: list[str] = field(default_factory=list)
instance: ClassVar[__OnlyOne | None] = None
def __init__(self, arg: str) -> None:
if OnlyOne.instance is None:
OnlyOne.instance = OnlyOne.__OnlyOne()
OnlyOne.instance.val.append(arg)
def __getattr__(self, name: str) -> Any:
return getattr(self.instance, name)
x = OnlyOne("sausage")
print(x.val)
#: ['sausage']
y = OnlyOne("eggs")
print(y.val)
#: ['sausage', 'eggs']
z = OnlyOne("spam")
print(z.val)
#: ['sausage', 'eggs', 'spam']
# Distinct wrappers (x is not y), one shared inner instance:
print(x is y, x.instance is y.instance is z.instance)
#: False TrueBecause the inner class’s name starts with a double
underscore, the compiler mangles it to
_OnlyOne__OnlyOne wherever it appears inside
OnlyOne’s body. OnlyOne.__OnlyOne,
written from outside the class, asks for an attribute that does
not exist under that name, so it fails at runtime with
AttributeError, not at type-checking time. The
outer class controls creation through its constructor. The first
construction of an OnlyOne initializes
instance. Every later one reuses that inner object,
and each construction appends its argument to that object’s
shared list. __getattr__() delegates access. Python
calls it only when ordinary attribute lookup fails, so a name
the wrapper does not have, such as val, falls
through to the inner object. The distinct OnlyOne
instances all proxy to the same __OnlyOne
object.
__getattr__() returns Any, and that
Any stays. instance is one declared
field and can say __OnlyOne | None, while
__getattr__() answers for every name Python fails
to find on the wrapper, so its return type is whatever the inner
object holds under that name, an open set no annotation can
list. Delegation gives up static knowledge to forward every
name, the cost Surrogate
pays throughout.
The laziness is a choice. When the inner object needs nothing
from that first call, you can create it eagerly in the
class body instead,
instance: ClassVar[__OnlyOne] = __OnlyOne(). That
removes the sentinel, the guard, and the first-call race the
cached factory met under threads, at the cost of building the
object whether or not anything uses it. (The bare
__OnlyOne() works because the nested class exists
at that point in the body. The qualified
OnlyOne.__OnlyOne() fails, since the name
OnlyOne stays unbound until its own class body
finishes running.) Exercise 1 makes that change.
Either way, OnlyOne is a lot of code for what a
module does on its own.
The nested private class is optional. Here you keep the
single instance in a class variable. __new__(), the
method that creates an instance, builds it when needed and
returns it as the result of every construction:
# singleton_class_variable.py
from typing import ClassVar
class SingletonClassVar:
val: list[str]
__instance: ClassVar[SingletonClassVar | None] = None
def __new__(cls, arg: str) -> SingletonClassVar:
if SingletonClassVar.__instance is None:
SingletonClassVar.__instance = (
object.__new__(cls))
SingletonClassVar.__instance.val = []
SingletonClassVar.__instance.val.append(arg)
return SingletonClassVar.__instance
x = SingletonClassVar("sausage")
y = SingletonClassVar("eggs")
z = SingletonClassVar("spam")
print(x.val, x is y is z, isinstance(x, SingletonClassVar))
#: ['sausage', 'eggs', 'spam'] True Trueobject.__new__(cls) builds a
SingletonClassVar, so every construction hands back
that same instance and isinstance() reports
True. Python honors whatever object
__new__() returns, and that return value decides
whether __init__() runs. When
__new__() returns an instance of the class under
construction, Python runs __init__() on it, so a
singleton __new__() triggers
__init__() on the shared instance after
every construction. SingletonClassVar
defines no __init__(), so __new__()
does all the work. A __new__() that returned some
other object would skip __init__() and fail
isinstance() as well.
Alex Martelli
observes that what you usually want is not one object but
one shared set of state. People can create as many objects as
they like, as long as they all share the same data. He called
that design the Borg.1 A Borg points every
instance’s __dict__ at the same storage:
The previous singleton designs stood alone; you reuse Borg through inheritance:
# singleton_borg.py
from typing import Any, ClassVar
class Borg:
_shared_state: ClassVar[dict[str, Any]] = {}
def __init__(self) -> None:
self.__dict__ = self._shared_state
class Singleton(Borg):
def __init__(self, arg: str) -> None:
super().__init__()
self.val = arg
def __str__(self) -> str:
return self.val
x = Singleton("sausage")
y = Singleton("eggs")
z = Singleton("spam")
# Last write wins: distinct objects, one shared __dict__:
print(x.val, x is y, x.__dict__ is y.__dict__ is z.__dict__)
#: spam False TrueThe nested class above was a @dataclass;
Singleton cannot be one. The sharing depends on
super().__init__ rebinding
self.__dict__ to _shared_state, and a
dataclass generates its own __init__ that assigns
the fields and never
calls the base __init__, so each instance keeps
its own __dict__. The code still runs; the class
has quietly stopped being a Borg. A
__post_init__ that does the rebinding fails
differently: it runs after __init__ has assigned
the fields, so the rebinding discards them. The hand-written
__init__ makes the sharing work, and silently
losing the sharing is worse than failing outright.
The sharing also reaches further than it looks.
_shared_state is one dict on Borg, so
every subclass shares it, not merely every instance of a single
subclass. A second subclass alongside Singleton
writes into the same dict, so constructing one of each leaves
both objects reading the value set last. A subclass that needs
storage of its own declares it:
class Singleton(Borg): _shared_state: ClassVar[dict[str, Any]] = {}.
The test confirms the objects differ but share one set of
state. Borg has no cache_clear(): whatever one test
leaves in _shared_state is still there for the
next. A pytest fixture closes that gap by clearing the dict
before each test:
# test_singleton_borg.py
import pytest
from singleton_borg import Borg, Singleton
@pytest.fixture(autouse=True)
def reset_shared_state() -> None:
Borg._shared_state.clear()
def test_borg_shares_state_but_not_identity() -> None:
x = Singleton("first")
y = Singleton("second")
assert x is not y # Distinct objects
assert x.val == y.val # But sharing one set of state
assert x.val == "second"
def test_pollutes_shared_state() -> None:
setattr(Singleton("first"), "extra", "leftover")
def test_fixture_cleared_it() -> None:
y = Singleton("second")
assert not hasattr(y, "extra") # Reset ranA class decorator can wrap a class so that calling it returns a cached instance:
# singleton_class.py
from typing import Any
class singleton:
def __init__(self, constructor: type) -> None:
self.constructor = constructor
self.instance: Any = None
def __call__(self, *args: Any, **kwargs: Any) -> Any:
print(f"singleton.__call__({args}, {kwargs})")
if self.instance is None:
print(
f"constructing {self.constructor.__name__}")
self.instance = self.constructor(
*args, **kwargs)
else:
print(
f"using cached {self.constructor.__name__}")
print(f"discarding {args}, {kwargs}")
return self.instance
@singleton
class Registry:
def __init__(self, name: str, *,
limit: int = 10) -> None:
print(f"Registry.__init__({name}, {limit})")
self.name = name
self.limit = limit
self.items: list[str] = []
first = Registry("primary", limit=3)
#: singleton.__call__(('primary',), {'limit': 3})
#: constructing Registry
#: Registry.__init__(primary, 3)
first.items.append("spam")
first.items.append("eggs")
second = Registry("secondary", limit=99)
#: singleton.__call__(('secondary',), {'limit': 99})
#: using cached Registry
#: discarding ('secondary',), {'limit': 99}
print(first is second, second.name,
second.limit, second.items)
#: True primary 3 ['spam', 'eggs']@singleton on Registry runs
Registry = singleton(Registry). The name
Registry now refers to the decorated instance
rather than to the class. Why does __call__()
intercept the constructor for a Registry? To
evaluate obj(...), Python looks up
__call__() on the type of obj
(Surrogate
examines this type-based lookup in full). For an ordinary class
C, type(C) is type, and
the parentheses run type.__call__(), the machinery
that invokes __new__() and then
__init__(). After decoration,
type(Registry) is singleton, so the
same parentheses run singleton.__call__() instead,
and the wrapped class’s constructor runs only when that method
decides to call it. __call__() forwards
*args and **kwargs to the constructor
of the wrapped class, so
Registry("primary", limit=3) reaches the real
constructor unchanged.
Only the first call constructs a Registry. Every
later constructor call returns the cached instance and discards
the constructor arguments, so
Registry("secondary", limit=99) creates no new
object. A caller who believes those arguments took effect holds
an object configured by someone else.
isinstance(first, Registry) and
class Sub(Registry) both raise:
# test_singleton_class.py
import pytest
from singleton_class import Registry
def test_isinstance_rejects_the_decorated_name() -> None:
with pytest.raises(TypeError,
match="arg 2 must be a type"):
isinstance(Registry("primary"), Registry) # type: ignore
def test_subclassing_the_decorated_name_fails() -> None:
with pytest.raises(TypeError,
match="takes 2 positional"):
class Sub(Registry): # type: ignore
passty and Pyright reject Sub
statically: its base has type singleton, not a
class. Under mypy, which does not apply a class decorator’s
return type, Registry is still a class and
Sub passes. At runtime the class
statement raises a TypeError.
singleton.__init__() takes two positional arguments
and receives four, because a class statement hands the name,
bases, and namespace to its metaclass, and Python takes that
metaclass from the type of the base, which is
singleton. Nothing in
class Sub(Registry) mentions
singleton, so the error names a class that does not
appear in the failing line. That is the confusion a class
decorator costs you. singleton_class_variable.py
keeps the name pointing at a real class, and that is the reason
to prefer it.
A metaclass can also intercept construction. Metaprogramming
shows that singleton: its metaclass overrides
__call__(), and that override skips
__init__() on every later construction, so the
first call’s arguments win. In a class that overrides
__new__() instead, as singleton_class_variable.py
does, __new__() still runs on every call, unlike
the metaclass form above. That listing puts its work inside
__new__() itself, so later calls append to the
shared instance instead of overwriting it. Metaprogramming
also covers __init_subclass__() and
__set_name__(), the simpler hooks that replace most
metaclasses. A singleton needs none of this machinery.
Use the lightest tool that fits:
@cache), or override
__new__() as singleton_class_variable.py
does. Under threads, prime the factory at import time or use the
module form.isinstance() check, or subclassing. A module
already shares that state with every importer and needs no
class, so shared data alone is no reason to use Borg.The elaborate GoF Design Patterns singleton is largely a workaround for languages where a module is not a first-class, single-instance namespace. In Python, most of the ceremony falls away.
singleton_pattern.py waits
for the first construction to build its inner object. Modify it
to use eager initialization, creating the inner
instance in the class body, and remove the sentinel and the
guard. What did the change cost, and which failure from Tests, Threads, and Locks
can no longer occur?singleton_cached_factory.py
as a starting point, create a factory that manages a fixed pool
of objects (say, database connections) and hands them out,
rather than a single instance.shared_config.py, replace
the mutation with a rebinding,
settings = {"theme": "dark"}, and add
import config plus
print(config.settings) at the end. Predict both
printed values before running it, and explain the difference
using the binding-versus-mutation distinction from A Module Is Already a
Singleton.threading.Lock inside
settings() in singleton_cached_race.py,
wrapping only the body of the cached function, and run it.
Explain why the object count does not drop to one, then fix it
without a lock.singleton_borg.py a second
Borg subclass and construct one of each. Explain
the value you get back, and change the code so the two
subclasses keep separate shared state.