单例模式
作用
只生成一个实例对象,减少了对系统资源的开销,当一个对象的产生需要比较多的资源,如读取配置文件,产生其他依赖对象时,可以产生一个单例对象,然后永久驻留在内存中,从而极大的降低开销
应用
- 使用框架时只加载一次配置文件
- scrapy框架中管道文件与数据库建立连接和断开连接只执行一次
- python的模块就是天生的单例模式。导入一次之后就不会再次导入
实现单例的几种方式
- 使用模块
python的模块就是天然的单例模式,模块在第一次导入时会生成.pyc文件,当第二次导入时,就会直接加载.pyc文件,而不会再次执行模块代码 - 使用装饰器
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:
pass
a1 = A()
a2 = B()
print(a1)
print(a2) #打印出来的对象a1,a2地址是一样的,实现了单例
- 使用__new__(cls)
推荐使用,方便
#模型示例
class Mysingleton:
#通过__obj类属性保存该类创建的单例
__obj = None
#加一个标记
__init_flag = True
#重写魔法函数__new__(cls)
#魔法函数_new__(cls)用于创建类实例,在你实例化类时,在__init__()之前调用
def __new__(cls,*args,**kwargs):
#如果类属性为空,则调用object类的__new__()创建类实例
if cls.__obj == None:
cls.__obj = super().__new__(cls)
return cls.__obj
#__init__()在你创建了类实例之后调用
def __init__(self,name):
#如果类属性__init_flag为True,则执行一次,之后就不执行了
if Mysingleton.__init_flag:
print("init....")
self.name = name
MySingleTon.__init_flag = False
a = MySingleton("aa") #会打印出init....
b = MySingleton("bb") #不再打印出init...
print(a)
print(b)
#打印出来的a和b的地址是一样的,说明打印出来的是一个对象
#示例2
class CarFactory:
#类属性
#存放单例
__obj = None
__init_flag = True
def create_car(self,brand):
if brand == "奔驰":
return Benz()
else brand == "宝马":
return BMW()
elif brand == "比亚迪":
return BYD()
else:
return "未知名品牌,无法创建"
def __new__(cls,*args,**kwargs):
if cls.__obj == None:
cls.__obj = object.__new__(cls)
return cls.__obj
def __init__(self):
if CarFactory.__init._flag:
print("init CarFactory....")
CarFactory.__init_flag = False
class Benz:
pass
class BMW:
pass
class BYD:
pass
factory = CarFactory()
c1 = factory.create_car("奔驰")
print(c1) #init CarFactory...只打印一次
c2 = factory.create_car("比亚迪")
print(c2)
factory2 = CarFactor()
print(factory)
print(factory2) #factory2和factory对象地址一样,说明是同一个实例(单例)