It's not clear to me how the typical metaclass singleton implementation works. I would expect the starred print to execute twice; it only happens once:
class _Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
print('Within __call__', cls, cls._instances, *args, **kwargs)
if cls not in cls._instances:
print('**About to call __call__', super(_Singleton, cls).__call__, flush=True)
print("Is cls the '...of object'?", hex(id(cls)).upper())
cls._instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
print(cls._instances[cls])
return cls._instances[cls]
class MySingleton(metaclass=_Singleton):
pass
if __name__ == '__main__':
print('Making mysingleton')
mysingleton = MySingleton()
print("Is mysingleton the 'cls'?", mysingleton)
print('Making another')
another = MySingleton()
# Verify singletude
assert another == mysingleton
This prints
Making mysingleton
Within __call__ <class '__main__.MySingleton'> {}
**About to call __call__ <method-wrapper '__call__' of _Singleton object at 0x000001C950C28780>
Is cls the '...of object'? 0X1C950C28780
<__main__.MySingleton object at 0x000001C9513FCA30>
Is mysingleton the 'cls'? <__main__.MySingleton object at 0x000001C9513FCA30>
Making another
Within __call__ <class '__main__.MySingleton'> {<class '__main__.MySingleton'>: <__main__.MySingleton object at 0x000001C9513FCA30>}
As is my experience with the Python docs, they're terribly circular and confusing. The docs say that __call__() is called when an instance is "called". Fair enough; MySingleton.__call__ is run because the "()" on mysingleton = MySingleton() indicates a function call. MySingleton is of the _Singleton type, so it has an _instances dict. The dict is naturally empty on first call. The conditional fails and Super(_Singleton, cls).__call__ executes.
What does super() do here? It's barely intelligible from the docs. It returns a "proxy object", explained elsewhere as "an object which 'refers' to a shared object", that delegates method calls to a parent or sibling class of 'type'. Okay, fine; it will be used to call a method of some related _Singleton type.
The two argument form of super(), which is used here, "specifies the arguments exactly and makes the appropriate references". What references are those? The type is _Singleton and object is cls, which isn't mysingleton. It's whatever object 0x000001C950C28780 is. Anyway, the super() search order is that of getattr() or super(). I think that means references are looked up according to _Singleton.__mro__ since __call__ isn't an attribute (or is it?). That is, the super() call looks up according to super(), which I assume is _Singleton. Clear as mud. The __mro__ yields (<class '__main__._Singleton'>, <class 'type'>, <class 'object'>). So, super(_Singleton, cls) will look for the "related _Singleton type" and call its __call__ method; I assume that's cls.__call__().
Since cls is a _Singleton, I would expect to see the second print. Actually, I would expect some kind of recursion. Neither happen. What's going on in there?