I was messing around with metaclasses a little bit trying to figure out how I may use one to create a singleton data structure when I came across something that's stumped me:
Also, I have done my homework and looked at this page and this one too, but I wanted to see if I could do it on my own and the problem that arose is less about how to implement a singleton and more about the functionality of something in my version of a singleton metaclass.
class SingletonError(Exception):
pass
class Singleton(type):
def __new__(metacls, name, parents, kwargs):
cls = super(Singleton, metacls).__new__(metacls, name, parents, kwargs)
cls._instance = None
return cls
def __call__(cls, *args, **kwargs): #cls is the class being called, in this case
#when Quux is called, the Quux class is sent
#as the cls argument.
if not cls._instance:
inst = cls.__new__(cls, *args, **kwargs)
cls._instance = inst
else:
raise SingletonError("Cannot initialize multiple singletons")
print('returning', cls._instance)
return cls._instance
class Quux(metaclass = Singleton):
pass
Most of it works, like it does indeed raise a SingletonError when trying to initialize multiple instances of Quux
, but watch what happens when I try to create an instance of Quux
:
>>> q = Quux()
returning <__main__.Quux object at 0x02BE7E90>
>>> type(q)
<class '__main__.Quux'>
Does this mean that the __call__
method in the Singleton metaclass is returning the class object as opposed to the instance created in the __call__
method? If so, how may I fix it with the current setup I have?
(I realize there are better ways of creating a singleton but for the sake of this exercise and learning about metaclasses I would like to solve it with this setup).
EDIT: Okay, so BrenBarn just pointed out that I made a major derp and thought that when it type returned it was returning the class when really if it were returning the class object it would say . Sorry about the confusion.
But now I have a new problem: lets assume I have a __new__
method for the Quux
class.
class Quux(metaclass = Singleton):
def __new__(cls, thing):
name = cls.__name__
parents = cls.__bases__
kwargs = {'thing' : thing}
return super(Quux, cls).__new__(cls, thing)
It raises a TypeError saying that object.__new__() takes no parameters
. How can I fix this __new__
method to return an instance of the Quux class?