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 — это один и тот же объект в памяти