Skip to main content

Comparing Two Singleton Implementations in Python

Comparing Two Singleton Implementations in Python

Simpler version

Uses one class-level instance and keeps the whole mechanism in __new__().

Nested version

Separates the access layer from the state-holding object, but adds more indirection.

Real comparison

This is mostly directness versus layering, not lazy versus eager construction.

Introduction

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.

Simpler version

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.

Nested version

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 simple version does well

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 does well

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.

Complexity cost

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.

Shared behavior

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.

Practical takeaway Both patterns delay instance creation until first use. The real question is whether the added structure is clarifying the design or just making the pattern harder to read.
Best beginner path

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 to keep

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.

FAQ

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

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 .

Raell Dottin

Comments