单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
我们在使用class创建类的时候, 只会创建一个类对象, 但是, 当我们实例化这个类对象的时候, 一个类对象, 可以实例化出很多不同的对象, 而我们每次实例化出来一个对象, 就会在内存中重新分配一块空间, 而今天介绍的单例模式, 就是为了解决上述问题, 使得由一个类对象所实例化出来的全部对象都指向同一块内存空间.
要想弄明白为什么每个对象被实例化出来之后, 都会重新被分配出一块新的内存地址, 就要清楚一个python中的内置函数__new__(), 它跟__init__()一样, 都是对象在被创建出来的时候, 就自动执行的一个函数, init()函数, 是为了给函数初始化属性值的, 而__new__()这个函数, 就是为了给对象在被实例化的时候, 分配一块内存地址, 因此, 我们可以重写__new__()这个方法, 让他在第一次实例化一个对象之后, 分配一块地址, 在此后的所有实例化的其他对象时, 都不再分配新的地址, 而继续使用第一个对象所被分配的地址, 因此, 我们可以在类对象里, 定义一个类属性, 初始值设为None, 如果这个值是None就调用父类的__new__()方法, 为其分配地址, 并返回这个地址(__new__方法一定要返回一个地址)
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
每次实例化一个对象时,都会先调用 __new__() 创建一个对象,再调用 __init__() 函数初始化数据。因而,在 new 函数中判断 ExecSql类 是否已经实例化过,如果不是,调用父类的 new 函数创建实例;否则返回之前创建的实例。
_instance 作为类属性,保证了所有对象的 _instance 都是同一个,我们可以看到下面例子中多个实例化的内存地址是一样的,是最新实例的值
单例实际是当多处调用进行多次实例化时,当类已实例化过,直接用实例化好的对象,当类未实例化过时,进行实例化对象,多处调用进行多次实例化实际只发生了一次实例化,共用1个实例化对象内存地址,所以实例对象是一样的
class ExecSql(object):_instance=Nonedef __new__(cls,*args,**kwargs):print("实例化时优先调用new方法,创建实例对象,这个方法是实现单例")if cls._instance is None:cls._instance=super().__new__(cls)return cls._instancedef __init__(self,name,age):print("实例化时,初始化方法,初始化一些数据")self.name=nameself.age=agetest1 = ExecSql("橙子",18)
print(id(test1),id(test1.name),test1.name)test2 = ExecSql("柚子",33)
print(id(test1),id(test1.name),test1.name)
print(id(test2),id(test2.name), test2.name)"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/Test/test/test02.py
实例化时优先调用new方法,创建实例对象,这个方法是实现单例
实例化时,初始化方法,初始化一些数据
2668768588352 2668766898976 橙子
实例化时优先调用new方法,创建实例对象,这个方法是实现单例
实例化时,初始化方法,初始化一些数据
2668768588352 2668768524368 柚子
2668768588352 2668768524368 柚子Process finished with exit code 0