Notes and exercises for learning design patterns
__new__The important change is in __new__:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
__new__ runs before __init__. It is the method that actually creates or returns an object.
So the first call creates the settings object. Later calls return the cached object.
__init__ needs a guardEven if __new__ returns the same object, Python still calls __init__ after construction syntax:
AppSettings(environment="production", debug=True)
Without a guard, this would reset the existing object every time.
That is why the solution uses:
if getattr(self, "_initialized", False):
return
The first call initializes the object. Later calls return immediately.
The tests check four ideas:
This implementation makes the class responsible for its own creation rules. That is fine for learning, but in larger applications a module-level object or dependency injection can be clearer.