i've this implementation of singleton pattern in python, but i've noticed that the init is called, uselessly, everytime i call MyClass, despite the same instance is returned.
How can i avoid it?
class Test(object):
def __init__(self, *args, **kwargs):
object.__init__(self, *args, **kwargs)
class Singleton(object):
_instance = None
def __new__(cls):
if not isinstance(cls._instance, cls):
cls._instance = object.__new__(cls)
return cls._instance
class MyClass(Singleton):
def __init__(self):
print("should be printed only 1 time")
self.x=Test()
pass
a = MyClass() # prints: "should be printed only 1 time"
b = MyClass() # prints ( again ): "should be printed only 1 time"
print(a,b) # prints: 0x7ffca6ccbcf8 0x7ffca6ccbcf8
print(a.x,b.x) # prints: 0x7ffca6ccba90 0x7ffca6ccba90
The problem is that __new__
doesn't return an object, it returns an unitialized object on which __init__
is called afterwards.
You can't avoid that at all. What you can do is the following(using metatypes):
class Singleton(type):
def __init__(self, name, bases, mmbs):
super(Singleton, self).__init__(name, bases, mmbs)
self._instance = super(Singleton, self).__call__()
def __call__(self, *args, **kw):
return self._instance
class Test(metaclass = Singleton):
# __metaclass__ = Singleton # in python 2.7
def __init__(self, *args, **kw):
print("Only ever called once")
Another simple, but totally viable way to implement what you want, which doesn't require super or meta classes, is to just make your class a Python module, which are essentially Singleton objects.
Here's what I mean:
myclass.py
:
class Test(object):
pass
class MyClass(object):
def __init__(self):
print("in MyClass.__init__, should be printed only 1 time")
self.x = Test()
def __call__(self, *args, **kwargs):
classname = type(self).__name__
return globals()[classname]
MyClass = MyClass()
client.py
:
from myclass import MyClass
a = MyClass()
b = MyClass()
print(a, b)
print(a.x, b.x)
Output:
in MyClass.__init__, should be printed only 1 time
<myclass.MyClass object at 0x02200B30> <myclass.MyClass object at 0x02200B30>
<myclass.Test object at 0x02200C10> <myclass.Test object at 0x02200C10>
It's possible to derive a subclass from MyClass, but you'd have to do it something like this:
class Derived(type(MyClass)):
def __init__(self):
print("in Derived.__init__, should be printed only 1 time")
Derived = Derived()
Afterwards you could add this to 'client.py':
from myclass import Derived
a = Derived()
b = Derived()
print(a,b)
print(a.x,b.x) # AttributeError: 'Derived' object has no attribute 'x'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With