一、什么是单例模式
一个类,不断地实例化得到的对象,其实都是不同的对象
如果一个类实例化的对象永远是同一个对象的话,那么就可以称之为单例模式
比如,某个服务器的配置信息存在在一个文件中,客户端通过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、调用类
思路就是, 调用类自定义的 _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__
方法
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self, *args, **kwargs):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
with Singleton._instance_lock:
if not hasattr(cls, '_instance'):
Singleton._instance = super().__new__(cls)
return Singleton._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1, obj2)
def task(arg):
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task, args=[i, ])
t.start()