我们首先理解一下什么叫做单例模式。
就是说,系统环境里面有一个类,无论在系统的什么地方,只要想实例化,就只能得到一个实例,实例化后对实例的任何操作,也只和第一个实例相关。
另外一个层面,单例模式同样避免了重复实例化的内存浪费,如果使用得当,能够大大节约系统资源。
下面就说一下python里面实现实例的几种方法,里面有几个和我之前讲过的知识点相关,这里mark一下:
- 使用模块
- 使用魔法方法 __new__
- 使用装饰器
1.模块方法实施单例模式,这个方法很简单,很土,但是很好理解:
singleton.py
import datetime
class ModuleSingleton(object):
def __init__(self):
self.init_time = str(datetime.datetime.now())
def gatherAttrs(self):
return ",".join("{}={}".format(k, getattr(self, k))
for k in self.__dict__.keys())
def __str__(self):
return "[{}:{}]".format(self.__class__.__name__, self.gatherAttrs())
__repr__ = __str__
myinstance = ModuleSingleton()
下面我们来测试一下:
test.py
from singleton import test_module_singleton
def get_first_instance():
return test_module_singleton.myinstance
def get_second_instance():
return test_module_singleton.myinstance
def main():
obj1 = get_first_instance()
obj2 = get_second_instance()
print obj1, obj2
print id(obj1), id(obj2)
if __name__ == '__main__':
main()
下面是输出,发现他们的初始化时间,以及实例的id,完全一模一样。:
pydev debugger: starting (pid: 16531) [ModuleSingleton:init_time=2018-03-11 15:21:39.690618] [ModuleSingleton:init_time=2018-03-11 15:21:39.690618] 140711470863632 140711470863632
2.使用__new__方法实现单粒,这里的__dict__,super,__init__请自行脑补一下:
import datetime
class MagicNewSingleton(object):
_instance = None
def __new__(cls, *args, **kw):
if not cls._instance:
cls._instance = super(MagicNewSingleton, cls).__new__(cls, *args, **kw)
return cls._instance
def __init__(self):
self.init_time = str(datetime.datetime.now())
def gatherAttrs(self):
return ",".join("{}={}".format(k, getattr(self, k))
for k in self.__dict__.keys())
def __str__(self):
return "[{}:{}]".format(self.__class__.__name__, self.gatherAttrs())
__repr__ = __str__
obj1 = MagicNewSingleton()
obj2 = MagicNewSingleton()
print obj1, obj2
print id(obj1), id(obj2)
我们看一下输出结果,和第一种实现方式一样的效果:
[MagicNewSingleton:init_time=2018-03-11 15:40:33.918990] [MagicNewSingleton:init_time=2018-03-11 15:40:33.918990] 139931646473232 139931646473232
3.使用装饰器实现单粒模式,这里有关装饰器,闭包的内容,请自行脑补一下吧:
import datetime
from functools import wraps
def decorator_singleton(cls):
instances = {}
@wraps(cls)
def getinstance(*args, **kw):
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return getinstance
@decorator_singleton
class DecoratorSingleton(object):
def __init__(self)
self.init_time = str(datetime.datetime.now())
def gatherAttrs(self):
return ",".join("{}={}".format(k, getattr(self, k))
for k in self.__dict__.keys())
def __str__(self):
return "[{}:{}]".format(self.__class__.__name__, self.gatherAttrs())
__repr__ = __str__
if __name__ == '__main__':
obj1 = DecoratorSingleton()
obj2 = DecoratorSingleton()
print obj1, obj2
print id(obj1), id(obj2)
最后看一下输出:
[DecoratorSingleton:init_time=2018-03-11 15:51:50.268966][DecoratorSingleton:init_time=2018-03-11 15:51:50.268966]
140602111509648 140602111509648
总结一下:
- 模块方法,只需要在一个模块里面完成实例化,在其他模块使用时直接导入即可。(详细的,请先理解模块的概念,包括locals(), globals()两个方法)。
- __new__方法,重新实现类的'构造函数',使用类变量辨识类是否完成了初始化。
- 装饰器方法,使用闭包变量来辨识类是否完成了初始化。