__new__ is called for every MyClass(...) call. If it didn't get called, it would not be able to return the singleton instance.
And when the __new__ method returns an object and that object is an instance of the cls argument passed to __new__ (or a subclass), then the __init__ method is also called.
So, for each MyClass(...) call, __new__ is called. The __new__ method always returns an instance of the current class, so __init__ is called, every time. It doesn't matter here that it is the same instance each time.
From the __new__ method documentation:
If __new__() returns an instance of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to __new__().
You can see this happen if you add some print() calls in the methods:
>>> class Singleton(object):
... _instance = None
... def __new__(class_, *args, **kwargs):
... print(f'Calling {class_!r}(*{args!r}, **{kwargs!r})')
... if not isinstance(class_._instance, class_):
... print(f'Creating the singleton instance for {class_!r}')
... class_._instance = object.__new__(class_)
... return class_._instance
...
>>> class MyClass(Singleton):
... num_of_instances = 0
... def __init__(self, real=5, imaginary=6):
... print(f'Calling {type(self)!r}.__init__(self, real={real!r}, imaginary={imaginary!r})')
... self.real = real
... self.imaginary = imaginary
... MyClass.num_of_instances += 1
...
>>> a = MyClass(10, 20)
Calling <class '__main__.MyClass'>(*(10, 20), **{})
Creating the singleton instance for <class '__main__.MyClass'>
Calling <class '__main__.MyClass'>.__init__(self, real=10, imaginary=20)
>>> b = MyClass()
Calling <class '__main__.MyClass'>(*(), **{})
Calling <class '__main__.MyClass'>.__init__(self, real=5, imaginary=6)
You can't prevent the automatic __init__ call, at least not without overriding something else. If you want to avoid __init__ being called each time, you have some options:
You don't have to use an __init__ method on the subclass. You could invent your own mechanism, __new__ could look for a __singleton_init__ method and call that:
class Singleton(object):
_instance = None
def __new__(class_, *args, **kwargs):
if not isinstance(class_._instance, class_):
class_._instance = object.__new__(class_)
if hasattr(class_._instance, '__singleton_init__'):
class_._instance.__singleton_init__(*args, **kwargs)`
return class_._instance
or your __init__ method could check if there are already attributes set in vars(self) (or self.__dict__) and just not set attributes again:
class MyClass(Singleton):
def __init__(self, real=5, imaginary=6):
if vars(self):
# we already set attributes on this instance before
return
self.real = real
self.imaginary = imaginary
The __new__ and __init__ logic is implemented in type.__call__; you could create a metaclass that overrides that logic. While you could simply call __new__ only (and leave everything as is), it makes sense to make the metaclass responsible for handling the Singleton pattern:
class SingletonMeta(type):
def __new__(mcls, *args, **kwargs):
cls = super().__new__(mcls, *args, **kwargs)
cls._instance = None
return cls
def __call__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__call__(*args, **kwargs)
return cls._instance
then use this not as a base class but with metaclass=.... You can create an empty base class if that's easier:
class Singleton(metaclass=SingletonMeta):
pass
class MyClass(Singleton):
# ...
The above will call __new__ on the class, optionally followed by __init__ on the resulting instance, just once. The SingletonMeta.__call__ implementation then, forever after, returns the singleton instance without further calls:
>>> class SingletonMeta(type):
... def __new__(mcls, *args, **kwargs):
... cls = super().__new__(mcls, *args, **kwargs)
... cls._instance = None
... return cls
... def __call__(cls, *args, **kwargs):
... print(f'Calling {cls!r}(*{args!r}, **{kwargs!r})')
... if cls._instance is None:
... cls._instance = super().__call__(*args, **kwargs)
... return cls._instance
...
>>> class Singleton(metaclass=SingletonMeta):
... pass
...
>>> class MyClass(Singleton):
... def __init__(self, real=5, imaginary=6):
... print(f'Calling {type(self)!r}.__init__(self, real={real!r}, imaginary={imaginary!r})')
... self.real = real
... self.imaginary = imaginary
...
>>> a = MyClass(10, 20)
Calling <class '__main__.MyClass'>(*(10, 20), **{})
Calling <class '__main__.MyClass'>.__init__(self, real=10, imaginary=20)
>>> MyClass()
Calling <class '__main__.MyClass'>(*(), **{})
<__main__.MyClass object at 0x10bf33a58>
>>> MyClass() is a
Calling <class '__main__.MyClass'>(*(), **{})
True
>>> MyClass().real
Calling <class '__main__.MyClass'>(*(), **{})
10