在 python 里实现单例模式有许多方法,个人觉得还是基于 decorator 的方法最优雅。
从 stackoverflow 上找到一个实现,我将它改成了线程安全的,记录如下:
import threading
class Singleton:
"""
A class to ease implementing singletons.
This should be used as a decorator -- not a metaclass -- to the
class that should be a singleton.
The decorated class can define one `__init__` function that
takes only the `self` argument. Other than that, there are
no restrictions that apply to the decorated class.
To get the singleton instance, use the `Instance` method. Trying
to use `__call__` will result in a `TypeError` being raised.
Limitations: The decorated class cannot be inherited from.
"""
def __init__(self, decorated):
self._decorated = decorated
self.lock = threading.Lock()
def Instance(self):
"""
Returns the singleton instance. Upon its first call, it creates a
new instance of the decorated class and calls its `__init__` method.
On all subsequent calls, the already created instance is returned.
"""
try:
return self._instance
except AttributeError:
self.lock.acquire()
try:
return self._instance
except AttributeError:
self._instance = self._decorated()
return self._instance
finally:
self.lock.release()
def __call__(self):
raise TypeError('Singletons must be accessed through `Instance()`.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)
使用时,只要未需要实现 singleton 的类添加一个 decorator 就可以了,如下:
@Singleton
class MySingletonClass: pass
s1 = MySingletonClass.Instance()
s2 = MySingletonClass.Instance()
s1 和 s2 就是相同的实例。
附上一个简单的 testcase:
import unittest
from singleton import Singleton
@Singleton
class A: pass
class TestSingleton(unittest.TestCase):
def testSingleton(self):
a = A.Instance()
aa = A.Instance()
self.assertTrue(a is aa)
def testSingletonCall(self):
self.assertRaises(TypeError, A)
def testIsinstance(self):
a = A.Instance()
self.assertTrue(isinstance(a, A))
self.assertFalse(isinstance(a, list))
if __name__ == "__main__":
unittest.main()