目录
一、什么是单例模式
一个类,不断地实例化得到的对象,其实都是不同的对象
如果一个类实例化的对象永远是同一个对象的话,那么就可以称之为单例模式
比如,某个服务器的配置信息存在在一个文件中,客户端通过AppConfig类来读取配置文件的信息.
如果程序的运行的过程中,很多地方都会用到配置文件信息,则就需要创建很多的AppConfig实例,这样就导致内存中有很多AppConfig对象的实例,造成资源的浪费.其实这个时候AppConfig我们希望它只有一份,就可以使用单例模式.
二、实现单例模式的方法
2.1、使用模块
一个模块在第一次导入的时候,会执行模块代码,生成.pyc文件,当第二次导入的时候,就会直接加载.pyc文件。
我们把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了
新建一个python模块叫singleton,然后放入一个 py 文件,取名为 mysingleton.py
mysingleton.py
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
使用
from singleton.mysingleton import singleton
这样,每次拿到的都是同一个对象
2.2、使用装饰器
def singleton(cls):
# 单下划线的作用是这个变量只能在当前模块里访问,仅仅是一种提示作用
# 创建一个字典用来保存类的实例对象
_instance = {}
def _singleton(*args, **kwargs):
# 先判断这个类有没有对象
if cls not in _instance:
_instance[cls] = cls(*args, **kwargs) # 创建一个对象,并保存到字典当中
# 将实例对象返回
return _instance[cls]
return _singleton
@singleton
class A():
a = 1
def __init__(self, x=0):
self.x = x
print('这是A的类的初始化方法')
a1 = A(2)
a2 = A(3)
print(a1.__dict__ ,a2.__dict__)
print(id(a1), id(a2))
2.3、调用类-基于 classmethod 装饰器
思路就是, 调用类自定义的 _instance属性 , 这样有一个弊端就是在使用类创建的时候,并不是单例了.也就是说在创建类的时候一定要用类里面规定的方法创建
class Singleton(object):
def __init__(self,*args,**kwargs):
pass
@classmethod
def get_instance(cls, *args, **kwargs):
# 利用反射,看看这个类有没有_instance属性
if not hasattr(Singleton, '_instance'):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
s1 = Singleton() # 使用这种方式创建实例的时候,并不能保证单例
s3 = Singleton()
print(id(s1),id(s3))
s2 = Singleton.get_instance() # 只有使用这种方式创建的时候才可以实现单例
s4 = Singleton.get_instance()
print(id(s2),id(s4))
这种方法过于复杂并不推荐使用
import time
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self,*args,**kwargs):
time.sleep(1)
@classmethod
def get_instance(cls,*args,**kwargs):
if not hasattr(Singleton,'_instance'):
with Singleton._instance_lock:
if not hasattr(Singleton,'_instance'):
Singleton._instance = Singleton(*args,**kwargs)
return Singleton._instance
def task(arg):
obj = Singleton.get_instance(arg)
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
obj = Singleton.get_instance()
print(obj)
2.4、重写__new__
方法
1、一个对象的实例化过程是先执行类的
__new__方法
,如果我们没有写,默认会调用object的__new__
方法,返回一个实例化对象,然后再调用__init__方法
,对这个对象进行初始化,我们可以根据这个实现单例.
2、在一个类的__new__方法中
先判断是不是存在实例,如果存在实例,就直接返回,如果不存在实例就创建
class Mysingle():
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'new_obj'):
cls.new_obj = super().__new__(cls)
return cls.new_obj
def __init__(self, name):
self.name = name
obj1 = Mysingle('frank')
print(id(obj1), obj1.__dict__)
obj2 = Mysingle('jason')
print(id(obj2), obj2.__dict__)
2.5 重写元类的 call 方法
class Single(type):
def __call__(self, *args, **kwargs):
if not hasattr(self,'new_obj'):
self.new_obj = super().__call__(*args, **kwargs)
return self.new_obj
class Mysingle(metaclass=Single):
def __init__(self, name):
self.name = name
obj1 = Mysingle('frank')
print(id(obj1), obj1.__dict__)
obj2 = Mysingle('jason')
print(id(obj2), obj2.__dict__)
**步骤分析: **
1:obj1 = Mysingle(‘frank’) --> 调用 Single 元类的_ _ call_ _ 方法
2:self.new_obj = None—>调用 type 元类的_ _ call_ _ 方法最终将初始化好的对象返回
3:将初始化好的对象 赋值给 new_obj 属性,然后Single 元类的_ _ call_ _ 方法 将这个对象返回 并赋值给 obj1
4:得到 obj1—>obj1._ _ dict _ _= {‘name’: ‘frank’}
5:obj2 = Mysingle(‘jason’) --> 调用 Single 元类的_ _ call_ _ 方法
6:self.new_obj 此时并不是 None —> 那么直接返回之前已经生成的对象,此时不经过 Mysingle类的_ _ init_ _ 方法
7:obj2 就是之前已经生成对象–> obj2._ _ dict _ _ = {‘name’: ‘frank’}