Объекты
a и
b указывают на один и тот же экземпляр класса Singleton, поэтому a is b возвращает
True. Это стало возможным благодаря специальной логике в методе
__new__, который отвечает за создание объекта. В классе Singleton есть класс-переменная
_instance, где хранится единственный созданный объект.
При первом вызове конструктора
Singleton(10) переменная
_instance пуста, и
__new__ создает новый объект. Этот объект сохраняется в _instance, и далее возвращается. При втором вызове
Singleton(20) метод
new видит, что
_instance уже существует, и возвращает его же, не создавая новый. Таким образом,
a и
b — это ссылки на один и тот же объект. Метод
__init__ при этом всё равно вызывается повторно, и устанавливает
self.value = 20, затирая предыдущее значение. Это тонкость:
__new__ управляет созданием, а
__init__ вызывается каждый раз, даже если объект не создавался заново. Такой шаблон называется синглтон — он гарантирует, что у класса будет только один экземпляр.
class Singleton:
_instance = None # Класс-переменная, где будет храниться единственный экземпляр
def __new__(cls, *args, **kwargs):
# Этот метод вызывается ПЕРЕД __init__, чтобы создать объект
if cls._instance is None:
# Если объект еще не создан — создаем его через стандартный способ
cls._instance = super().__new__(cls)
# Если уже создан — просто возвращаем его
return cls._instance
def __init__(self, value):
# Этот метод вызывается КАЖДЫЙ РАЗ, даже если объект уже существует
self.value = value # Значение перезаписывается при каждом вызове
# Создаем первый экземпляр
a = Singleton(10)
# Пытаемся создать второй экземпляр с другим значением
b = Singleton(20)
print(a.value) # 20 — потому что __init__ второй раз перезаписал значение
print(b.value) # 20 — это тот же объект, что и a, с тем же атрибутом
print(a is b) # True — это один и тот же объект в памяти