单例模式确保应用程序中始终只有一个存活的实例。例如你想要资源访问限制的时候,或者数据库连接类等等,再比如服务配置文件放在一个目录中,程序启动需要通过Configure类加载配置文件。如果每个程序都去实例化一个Configure类,尤其conf文件还比较大
这个时候就会造成内存浪费,这种情况单例模式就派上用场了。
单例模式有如下几种实现方式
1.使用带有函数或者变量的模块,如数据库连接的的配置文件
MONGODB = "xxx" MYSQL = "xxx" REDIS = "xxx"
将它们保存在settings.py的文件中,然后其他程序直接导入即可,python这种导入本身就是单例模式的实现。
from settings import MONGODB
如果需要单例的类就实例化
class Singleton(object): pass singleton = Singleton()
然后导入实例化之后的方法就可以了
from xxx import singleton
2.使用单例模糊的装饰器
def Singleton(cls): cls_instance = {} def is_instance(*args, **kargs): if cls not in cls_instance: cls_instance[cls] = cls(*args, **kargs) return cls_instance[cls] return is_instance @Singleton class SingletonTest(object): def __init__(self, v): self.value = v t = SingletonTest(2) t2 = SingletonTest(3) print(t.value, t2.value) print(id(t) == id(t2))
>>> 2, 2
>>> True
3.使用__new__实现
在类实例化的时候,python首先调用__new__方法,然后在执行__init__进行初始化。所以我们可以在__new__做手脚。
class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls, *args, **kwargs) return cls._instance t1 = Singleton() t2 = Singleton() print(id(t1) == id(t2))
>>> True
注意: 这样写非常危险,如果你已经创建了一个基类,然后你尝试对基类的子类进行实例化,这个时候问题就出现了。
结果都会依赖实例创建的顺序,父类先创建就会出问题,子类先创建就是正常的。在大型应用中这是难以预测的错误千万要注意。如果单例不会被子类实例化,这个方法就没有问题。
4.使用元类实现
class Singleton(type): _intances = {} def __call__(cls, *args, **kwargs): print(cls._intances) if cls not in cls._intances: cls._intances[cls] = super().__call__(*args, **kwargs) return cls._intances[cls] class SingletonTest(metaclass=Singleton): # 指定创建Foo的type为SingletonType def __init__(self, v): self.value = v obj = SingletonTest('xx') obj2 = SingletonTest('xxx') print(id(obj) == id(obj2)) print(obj.value, obj2.value)
通常我们实例化都会生成一个新实例
1 class Singleton(object): 2 pass 3 4 a = Singleton() 5 b = Singleton() 6 print(id(a) == id(b))
>>> False