单例模式是常见的一种设计模式,它是针对类的一种描述,因此,我们可以使用python的decorator来实现通用的单例模式。
一.基本的单例模式
首先建立我们的decorator。我们需要为classType建立_instance和_lock成员:
Python
def singleton(classType):
classType._instance = None
classType._lock = Lock()
return classType
1
2
3
4
defsingleton(classType):
classType._instance=None
classType._lock=Lock()
returnclassType
然后为class建立getInstance函数:
Python
def __getInstance(classname):
if classname._instance is None:
classname._lock.acquire()
if classname._instance is None:
classname._instance = classname()
classname._lock.release()
return classname._instance
1
2
3
4
5
6
7
def__getInstance(classname):
ifclassname._instanceisNone:
classname._lock.acquire()
ifclassname._instanceisNone:
classname._instance=classname()
classname._lock.release()
returnclassname._instance
然后在我们的decorator中,将getInstance函数添加到class上:
Python
classType.getInstance = classmethod(__getInstance)
1
classType.getInstance=classmethod(__getInstance)
现在我们的代码长这样。这个decorator已经具备了基本功能:
Python
def __getInstance(classType):
if classType._instance is None:
classType._lock.acquire()
if classType._instance is None:
classType._instance = classType()
classType._lock.release()
return classType._instance
def singleton(classType):
classType._instance = None
classType._lock = Lock()
classType.getInstance = classmethod(__getInstance)
return classType
1
2
3
4
5
6
7
8
9
10
11
12
13
def__getInstance(classType):
ifclassType._instanceisNone:
classType._lock.acquire()
ifclassType._instanceisNone:
classType._instance=classType()
classType._lock.release()
returnclassType._instance
defsingleton(classType):
classType._instance=None
classType._lock=Lock()
classType.getInstance=classmethod(__getInstance)
returnclassType
使用方法如下:
Python
@singleton
class XXX(object):
# add class definitions
pass
1
2
3
4
@singleton
classXXX(object):
# add class definitions
pass
二.可继承的单例模式
现在让我们为这个单例模式添加一些功能:我们让被这个单例类可以产生子类,且子类也是单例类,和父类共享同一个instance。为此,我们必须修改被修饰的单例类的init方法,在其中设置instance为自身:
Python
def __singleton_init(self):
# check whether instance has existed
if self._instance is not None:
raise SingletonExistedError(type(self))
# set instance of this class and its ancestor classes to self
for baseClass in inspect.getmro(type(self)):
if '_instance' in baseClass.__dict__:
baseClass._instance = self
1
2
3
4
5
6
7
8
9
def__singleton_init(self):
# check whether instance has existed
ifself._instanceisnotNone:
raiseSingletonExistedError(type(self))
# set instance of this class and its ancestor classes to self
forbaseClassininspect.getmro(type(self)):
if'_instance'inbaseClass.__dict__:
baseClass._instance=self
SingletonExistedError为自定义的error类型:
Python
class SingletonExistedError(Exception):
def __init__(self, classType):
super(SingletonExistedError, self).__init__('trying to construct instance of singleton class ' + classType.__name__ + ' while an instance has already existed!')
1
2
3
classSingletonExistedError(Exception):
def__init__(self,classType):
super(SingletonExistedError,self).__init__('trying to construct instance of singleton class '+classType.__name__+' while an instance has already existed!')
现在我们需要把这个新的init函数添加到被修饰的单例类的init函数上。很自然的,我们又可以利用函数的decorator来办成这件事情,就像这样:
Python
def __singleton_init_decorator(init_func):
def __singleton_init(self):
# check whether instance has existed
if self._instance is not None:
raise SingletonExistedError(type(self))
# set instance of the class and ancestor singletons to self
for baseClass in inspect.getmro(type(self)):
if '_instance' in baseClass.__dict__:
baseClass._instance = self
init_func(self)
return __singleton_init
1
2
3
4
5
6
7
8
9
10
11
12
13
def__singleton_init_decorator(init_func):
def__singleton_init(self):
# check whether instance has existed
ifself._instanceisnotNone:
raiseSingletonExistedError(type(self))
# set instance of the class and ancestor singletons to self
forbaseClassininspect.getmro(type(self)):
if'_instance'inbaseClass.__dict__:
baseClass._instance=self
init_func(self)
return__singleton_init
最后,在我们的singleton decorator上加上这句代码:
Python
classType.__init__ = __singleton_init_decorator(classType.__init__)
1
classType.__init__=__singleton_init_decorator(classType.__init__)
大功告成!附上完整代码:
Python
class SingletonExistedError(Exception):
def __init__(self, classType):
super(SingletonExistedError, self).__init__('trying to construct instance of singleton class ' + classType.__name__ + ' while an instance has already existed!')
def __getInstance(classType):
if classType._instance is None:
classType._lock.acquire()
if classType._instance is None:
classType._instance = classType()
classType._lock.release()
return classType._instance
def __singleton_init_decorator(init_func):
def __singleton_init(self):
# check whether instance has existed
if self._instance is not None:
raise SingletonExistedError(type(self))
# set instance of the class and ancestor singletons to self
for baseClass in inspect.getmro(type(self)):
if '_instance' in baseClass.__dict__:
baseClass._instance = self
init_func(self)
return __singleton_init
def singleton(classType):
classType._instance = None
classType._lock = Lock()
classType.getInstance = classmethod(__getInstance)
classType.__init__ = __singleton_init_decorator(classType.__init__)
return classType
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
classSingletonExistedError(Exception):
def__init__(self,classType):
super(SingletonExistedError,self).__init__('trying to construct instance of singleton class '+classType.__name__+' while an instance has already existed!')
def__getInstance(classType):
ifclassType._instanceisNone:
classType._lock.acquire()
ifclassType._instanceisNone:
classType._instance=classType()
classType._lock.release()
returnclassType._instance
def__singleton_init_decorator(init_func):
def__singleton_init(self):
# check whether instance has existed
ifself._instanceisnotNone:
raiseSingletonExistedError(type(self))
# set instance of the class and ancestor singletons to self
forbaseClassininspect.getmro(type(self)):
if'_instance'inbaseClass.__dict__:
baseClass._instance=self
init_func(self)
return__singleton_init
defsingleton(classType):
classType._instance=None
classType._lock=Lock()
classType.getInstance=classmethod(__getInstance)
classType.__init__=__singleton_init_decorator(classType.__init__)
returnclassType