为什么 python 中的 Singleton 多次调用 __init__ 以及如何避免?
Why Singleton in python calls __init__ multiple times and how to avoid it?
我在 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
__init__
,如果实现,总是调用__new__
返回的任何内容;通常,您应该实施其中之一,而不是两者。相反,您可以在 MyClass
上实现 __new__
,并且仅当 x
属性尚不存在时才初始化它:
class MyClass(Singleton):
def __new__(cls):
inst = super(MyClass, cls).__new__(cls)
if not hasattr(inst, 'x'):
print("should be printed only 1 time")
inst.x = Test()
return inst
正在使用:
>>> a = MyClass()
should be printed only 1 time
>>> b = MyClass()
>>> a is b
True
>>> a.x is b.x
True
问题是 __new__
不是 return 对象,它 return 是一个单元化对象,之后会调用 __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")
另一个简单但完全可行的方法来实现你想要的东西,它不需要超级或元 classes,就是让你的 class 成为一个 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()
client.py
:
from myclass import MyClass
a = MyClass()
b = MyClass()
print(a, b)
print(a.x, b.x)
输出:
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>
可以从 MyClass 派生一个子class,但您必须这样做:
class Derived(type(MyClass)):
def __init__(self):
print("in Derived.__init__, should be printed only 1 time")
Derived = Derived()
之后您可以将其添加到 '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'
另一种创建单例对象的方法是让另一个 class 方法说 get_instance 这将确保您的 class 有一个单例对象..这是代码片段:
class Singleton(object):
__instance = None
@classmethod
def get_instance(cls):
if not cls.__instance:
Singleton()
return cls.__instance
def __init__(self):
if Singleton.__instance is None:
Singleton.__instance = self
print("Object initialized")
singleton_1 = Singleton.get_instance()
singleton_2 = Singleton.get_instance()
if singleton_1 is singleton_2:
print("Same")
else:
print("Different")
以上代码片段产生以下输出:
Object initialized
Same
我在 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
__init__
,如果实现,总是调用__new__
返回的任何内容;通常,您应该实施其中之一,而不是两者。相反,您可以在 MyClass
上实现 __new__
,并且仅当 x
属性尚不存在时才初始化它:
class MyClass(Singleton):
def __new__(cls):
inst = super(MyClass, cls).__new__(cls)
if not hasattr(inst, 'x'):
print("should be printed only 1 time")
inst.x = Test()
return inst
正在使用:
>>> a = MyClass()
should be printed only 1 time
>>> b = MyClass()
>>> a is b
True
>>> a.x is b.x
True
问题是 __new__
不是 return 对象,它 return 是一个单元化对象,之后会调用 __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")
另一个简单但完全可行的方法来实现你想要的东西,它不需要超级或元 classes,就是让你的 class 成为一个 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()
client.py
:
from myclass import MyClass
a = MyClass()
b = MyClass()
print(a, b)
print(a.x, b.x)
输出:
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>
可以从 MyClass 派生一个子class,但您必须这样做:
class Derived(type(MyClass)):
def __init__(self):
print("in Derived.__init__, should be printed only 1 time")
Derived = Derived()
之后您可以将其添加到 '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'
另一种创建单例对象的方法是让另一个 class 方法说 get_instance 这将确保您的 class 有一个单例对象..这是代码片段:
class Singleton(object):
__instance = None
@classmethod
def get_instance(cls):
if not cls.__instance:
Singleton()
return cls.__instance
def __init__(self):
if Singleton.__instance is None:
Singleton.__instance = self
print("Object initialized")
singleton_1 = Singleton.get_instance()
singleton_2 = Singleton.get_instance()
if singleton_1 is singleton_2:
print("Same")
else:
print("Different")
以上代码片段产生以下输出:
Object initialized
Same