I was trying to implement singleton classes for my project and an interesting post in StackOverflow on the same
Creating a singleton in Python
I decided to go with the metaclasses approach mentioned..
Now.. I tried to add a method to get and clear the instances (in case the user wants to get rid of the current instance and create a new one..):
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
def getInstance(cls):
print("Class is {}".format(cls.__name__))
if not cls in cls._instances:
raise LookupError("No instance of the class {cls} create yet.".format(cls.__name__))
return cls._instances[cls]
def clearInstance(cls):
cls._instances.pop(cls, None)
class someClass(metaclass=Singleton):
def __init__(self,val):
self.value = val
I am able to create objects successfully..
In [9]: sc = someClass(1)
In [10]: sc.value
Out[10]: 1
But when I do dir(someClass)
the 2 methods are not displayed:
In [14]: dir(someClass)
Out[14]:
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__']
Nevertheless I am able to call the methods..
In [13]: someClass.getInstance()
Class is someClass
Out[13]: <__main__.someClass at 0x7f728b180860>
In all the examples on metaclass I see online I see __new__
, __init__
and __call__
methods implemented but I don't see any additional methods added. Is it correct to add methods to the metaclass?
I also tried a small variation of the above metaclass code:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
@classmethod
def getInstance(cls):
print("Class is {}".format(cls.__name__))
if not cls in cls._instances:
raise LookupError("No instance of the class {cls} create yet.".format(cls.__name__))
return cls._instances[cls]
@classmethod
def clearInstance(cls):
cls._instances.pop(cls, None)
Marked the 2 methods as class method..
Now when I attempt to call them:
In [2]: sc = someClass(1)
In [3]: someClass.getInstance()
Class is Singleton
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-3-c83fe01aa254> in <module>()
----> 1 someClass.getInstance()
<ipython-input-1-9efb6548d92d> in getInstance(cls)
12
13 if not cls in cls._instances:
---> 14 raise LookupError("No instance of the class {cls} create yet.".format(cls.__name__))
15
16 return cls._instances[cls]
KeyError: 'cls'
As you can see the class is
print says its Singleton
when I decorate it as classmethod
. Otherwise it shows the correct class. I don't understand this behavior, can someone explain?