Comparing Two Singleton Implementations in Python
Uses one class-level instance and keeps the whole mechanism in __new__().
Separates the access layer from the state-holding object, but adds more indirection.
This is mostly directness versus layering, not lazy versus eager construction.
The Singleton pattern seems settled until you see it written two different ways. Then the real question shows up. If both versions promise one instance, what is actually changing between them? This post is about that comparison alone. Not whether Singleton is a good idea in general. Not when to use it. Just what changes when the same promise is expressed through two different shapes of Python code.
That makes this a useful beginner exercise because it separates the pattern from the styling around the pattern. Once you do that, you can start to see which parts are essential and which parts are extra structure.
The Simpler Version First
The most direct Python Singleton keeps one class-level instance and checks it inside
__new__().
class SingletonObject:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
This version is easy to read because the whole mechanism lives in one place. The class controls object creation directly, and every later construction attempt returns the same stored object.
first = SingletonObject()
second = SingletonObject()
print(first is second)
If that prints True, the pattern is working.
The Nested-Class Version
The more layered version splits the access point from the state-holding object. The outer class controls access. The inner class carries the actual payload.
class SingletonObject:
class __SingletonObject:
def __init__(self):
self.val = None
def __str__(self):
return f"{self!r} {self.val}"
instance = None
def __new__(cls):
if not SingletonObject.instance:
SingletonObject.instance = SingletonObject.__SingletonObject()
return SingletonObject.instance
def __getattr__(self, name):
return getattr(self.instance, name)
def __setattr__(self, name, value):
return setattr(self.instance, name, value)
This implementation still guarantees one instance, but it does so with more machinery. The outer layer is acting like a controlled doorway. The inner layer is the object that actually stores the state.
What the Simpler Version Gets Right
The obvious strength is readability. A beginner can usually understand it in one pass. There is no extra delegation layer, no nested payload object to track, and very little code standing between the reader and the core mechanism.
It also keeps the central promise in plain sight: one class, one stored instance, one check in
__new__().
What the Nested Version Gets Right
The nested-class Singleton is stronger on separation of roles, but it pays for that separation with more indirection.
That is the trade in one sentence. The nested version makes it clearer that one thing is controlling access while another thing is holding state. That can feel more disciplined in a design where that separation matters.
It also makes the state-holding object feel less exposed, because the inner class is tucked inside the outer definition.
Where the Extra Complexity Shows Up
The extra complexity is not hidden. You have a nested class. You have a stored instance on the
outer class. You have delegation methods like __getattr__() and
__setattr__(). That is more code to read and more behavior to explain.
For some projects, that structure may be justified. For a beginner trying to learn the mechanics of Singleton, it often slows down understanding more than it helps.
What Both Versions Still Share
They are both lazy in practice. Neither version creates the instance at import time merely because the class exists. Each one creates the instance only when the class is first called. That matters because one common comparison point is often described incorrectly.
So the real difference is not lazy versus eager. The real difference is directness versus layering.
What a Beginner Should Prefer First
For learning, the simpler version is the better starting point. It shows the essential idea without wrapping it in extra structure. Once that is clear, the nested version becomes easier to appreciate as a variation rather than as a puzzle.
That does not make the simpler version universally better. It only makes it the better teaching tool when the goal is to understand what the pattern itself is doing.
What a Beginner Should Keep
Both implementations enforce one instance. The simpler version emphasizes readability. The nested version emphasizes separation between the access layer and the payload. The right choice depends less on pattern loyalty and more on whether the extra structure is actually clarifying the design.
Frequently Asked Questions
These are the practical questions beginners usually have when comparing two Singleton implementations in Python.
Do both versions still count as Singleton implementations?
Yes. Both versions enforce one instance. They just express that promise through different structures.
What is the biggest advantage of the simpler version?
Readability. The mechanism is easy to see because the whole pattern lives in one class and one __new__() method.
What is the biggest advantage of the nested-class version?
Separation of roles. The outer class controls access, while the inner class carries the actual state.
Is the nested version more powerful?
Not automatically. It gives you a different structure, but the extra machinery only helps if that separation actually clarifies the design.
Is one version lazy and the other eager?
No. Both are lazy in practice because they create the instance only when the class is first called.
Why can the nested version feel harder to learn?
Because it adds delegation and another object layer, which means there is more to track before the reader reaches the core Singleton idea.
Which version should a beginner learn first?
Usually the simpler version. It teaches the essential mechanism without adding extra indirection too early.
What is the cleanest way to compare them?
Think of the simpler version as directness and the nested version as layering. That is the real contrast.
Further Reading
If you want the broader “when should I use Singleton at all?” question next, read When the Singleton Pattern Actually Helps .
If you want the Python-specific behavior angle next, read How Singleton Works in Python Without Leaning on Strict Types .
If you want the concurrency edge case next, read Why the Singleton Pattern Feels Simple Until It Doesn’t .
Comments