pythonsingleton

Singleton different behavior when using class and dict to store the instance


Why do these two base classes result in the child objects having different behavior?

class Base:

    _instance: "Base" = None

    def __new__(cls) -> "Base":
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

class A(Base):
    def foo(self):
        return "foo"

class B(Base):
    def quz(self):
        return "quz"

a = A()
b = B()

print(id(a))
print(id(b))
140035075937792
140035075948400

On the other hand

from typing import Dict

class Base:

    _instances: Dict[int, "Base"] = {} 

    def __new__(cls) -> "Base":
        if 0 not in cls._instances:
            cls._instances[0] = super().__new__(cls)
        return cls._instances[0]

class A(Base):
    def foo(self):
        return "foo"

class B(Base):
    def quz(self):
        return "quz"

a = A()
b = B()

print(id(a))
print(id(b))
140035075947296
140035075947296

Solution

  • When a = A() is executed, the __new__ method is called with the class A as its argument. This sets the value of the class attribute A._instance. Likewise, b = B() sets the value of B._instance.

    In the first case, the original value of Base._instance, A.instance and B._instance is None, which is a non-mutable object, so changing this value in A or B does not affect the other two classes.

    In the second case, A._instance, B._instance and Base._instance point to the same dictionary. Since a dictionary is a mutable object, modifying this dictionary via one class affect all three classes.