Jos*_*eph 3 python singleton initialization
我已经在python中实现了单例模式,但是我注意到了init,尽管返回了相同的实例,但每次我调用MyClass都会调用。
我该如何避免呢?
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
Run Code Online (Sandbox Code Playgroud)
问题是__new__不返回对象,而是返回一个统一的对象__init__此后进行调用。
您根本无法避免。您可以做以下事情(使用元类型):
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")
Run Code Online (Sandbox Code Playgroud)
另一种简单但完全可行的方法来实现你想要的,不需要超级类或元类,就是让你的类成为一个Python模块,它本质上是单例对象。
这就是我的意思:
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()
Run Code Online (Sandbox Code Playgroud)
client.py:
from myclass import MyClass
a = MyClass()
b = MyClass()
print(a, b)
print(a.x, b.x)
Run Code Online (Sandbox Code Playgroud)
输出:
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()
Run Code Online (Sandbox Code Playgroud)
可以从 MyClass 派生子类,但您必须这样做:
class Derived(type(MyClass)):
def __init__(self):
print("in Derived.__init__, should be printed only 1 time")
Derived = Derived()
Run Code Online (Sandbox Code Playgroud)
之后您可以将其添加到“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'
Run Code Online (Sandbox Code Playgroud)