Before you start
Singleton is the pattern most often used, and most often used WRONG. Read this before you write any code.
The most important thing
In Python, most singletons should just be module-level
objects, not classes with __new__ tricks.
# printer.py
class Printer: ...
printer = Printer() # one line. Done.
Every from printer import printer returns the same
object. Python's import system has been guaranteeing "one
object per program" since 1991. You don't need a pattern
for that.
Use a real Singleton class only when you need:
- The GUARANTEE that
Printer()can't build a second object (for real requirements the app has to enforce), OR - Runtime-picked behavior (
Printer.instance()picks the right kind based on the environment)
If you just want "one shared object" — use a module.
When Singleton is a fair choice
Actually rare list:
- A physical resource with only one. Real printer, real serial port, real GPU on an embedded system.
- A rule enforced by law or math. "There is one
system clock" (kind of —
datetimedoesn't actually enforce this). - A legacy library that assumes there's only one. You're wrapping it.
If your reason is "I only need one" — that's a module. Not a Singleton.
When Singleton is a mistake
- App config. Use a module-level
Configobject. Or pass a config into the services that need it. - Database connection. Use a module-level pool. Or pass one in.
- Logger. Python's
loggingmodule already handles this correctly, without exposing a Singleton class. - Cache. Same story.
- Whatever you were about to say. Really.
The internet is full of tutorials that have students writing 20-line Singleton implementations for things Python already handles in one line. Don't be that engineer in a code review.
The test problem
Singletons are the #1 cause of flaky test suites. Tests share state through the singleton, one test's setup poisons another, and debugging takes hours.
Fixes:
- Add a
_reset()method — every test resets it first. (We do this in the lesson.) - Use a pytest fixture that auto-resets with
autouse=True. - Or don't use Singleton at all — pass the printer in from outside.
The old "there's only ONE production instance" argument falls apart the moment you write tests. Tests want fresh state. Singletons make that hard.
Compared to module-level state
For the same problem, module-level would look like this:
# printer.py
class Printer:
def __init__(self): self._jobs = []
def submit(self, job):
self._jobs.append(job)
return f"queued {job} (position {len(self._jobs)})"
def jobs(self): return tuple(self._jobs)
_printer = Printer()
def printer():
return _printer
def _reset():
global _printer
_printer = Printer()
Same behavior. Half the code. Fewer traps. In Python this is almost always the right answer.
The class-based Singleton in this lesson is here so you can recognize it (interviewers ask), write it correctly, and KNOW when NOT to reach for it. That third one is the interview skill.
The decision cheat-sheet
For "should this be a singleton?":
| Situation | Answer |
|---|---|
| "Only one exists in production" | Module-level object |
| "Building two would corrupt state" | Class Singleton with .instance() (this lesson) |
| "Building two would waste memory" | Not a design concern — probably still module-level |
| "Multiple customers share the process, each needs its own" | NOT Singleton — pass it in |
| "Tests need fresh state each run" | Not Singleton, or Singleton with _reset() |
| "Config that changes per environment" | Pass a Config object in |
What the tests in this lesson do
- Shared state across callers — the singleton payoff.
_reset()works — the escape hatch for tests.- Direct
Printer()still allowed — Design D's advantage over the__new__version. Tests that want isolation don't have to poke inside the class.
In an interview
If asked "should this be a Singleton?" — pause. Ask the requirement questions from the objective. If the answer is "I need one shared object", say "in Python I'd use a module-level object rather than the Singleton pattern. Here's why...". That answer shows judgment.
If the interviewer specifically wants the Singleton pattern — write it. Show them the classmethod version (Design D). Mention that in real Python you'd usually just use module-level state. They'll respect the honesty.