"); //-->
今天扣丁学堂给大家介绍一下关于Python视频教程之创建单例模式五种方法的介绍,首先单例模式(SingletonPattern)是一种常用的软件设计模式,是指一个类的实例从始至终只能被创建一次,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

主要优点:
1、提供了对唯一实例的受控访问。
2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
3、允许可变数目的实例。
主要缺点:
1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
2、单例类的职责过重,在一定程度上违背了“单一职责原则”。
3、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
适用场景:
在以下情况下可以考虑使用单例模式:
-(1)系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。
-(2)客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
实现某个类只有一个实例的途径:
1,让一个全局变量使得一个对象被访问,但是他不能防止外部实例化多个对象。
2,让类自身保存他的唯一实例,这个类可以保证没有其他实例可以被创建。
多线程时的单例模式:加锁-双重锁定
饿汉式单例类:在类被加载时就将自己实例化(静态初始化)。其优点是躲避了多线程访问的安全性问题,缺点是提前占用系统资源。
懒汉式单例类:在第一次被引用时,才将自己实例化。避免开始时占用系统资源,但是有多线程访问安全性问题。
方法1:使用__new__方法
如果想使得某个类从始至终最多只有一个实例,使用__new__方法会很简单。Python中类是通过__new__来创建实例的:
classSingleton(object):
def__new__(cls,*args,**kwargs):
ifnothasattr(cls,'_inst'):
cls._inst=super(Singleton,cls).__new__(cls,*args,**kwargs)
returncls._inst
if__name__=='__main__':
classA(Singleton):
def__init__(self,s):
self.s=s
a=A('java')
b=A('python')
printid(a),a.s
printid(b),b.s
结果:
129621235python
9921235python
通过__new__方法,将类的实例在创建的时候绑定到类属性_inst上。如果cls._inst为None,说明类还未实例化,实例化并将实例绑定到cls._inst,以后每次实例化的时候都返回第一次实例化创建的实例。注意从Singleton派生子类的时候,不要重载__new__。
方法2:使用装饰器
我们知道,装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例,代码如下:
fromfunctoolsimportwraps
defsingleton(cls):
instances={}
@wraps(cls)
defgetinstance(*args,**kw):
ifclsnotininstances:
instances[cls]=cls(*args,**kw)
returninstances[cls]
returngetinstance
@singleton
classMyClass(object):
a=1
在上面,我们定义了一个装饰器singleton,它返回了一个内部函数getinstance,该函数会判断某个类是否在字典instances中,如果不存在,则会将cls作为key,cls(*args,**kw)作为value存到instances中,否则,直接返回instances[cls]。
方法3:使用元类(metaclass)
当你编写一个类的时候,某种机制会使用类名字,基类元组,类字典来创建一个类对象。新型类中这种机制默认为type,而且这种机制是可编程的,称为元类__metaclass__。
classSingleton(type):
def__init__(self,name,bases,class_dict):
super(Singleton,self).__init__(name,bases,class_dict)
self._instance=None
def__call__(self,*args,**kwargs):
ifself._instanceisNone:
self._instance=super(Singleton,self).__call__(*args,**kwargs)
returnself._instance
if__name__=='__main__':
classA(object):
__metaclass__=Singleton
a=A()
b=A()
printid(a),id(b)
结果:
14364565443645654
id是相同的。
例子中我们构造了一个Singleton元类,并使用__call__方法使其能够模拟函数的行为。构造类A时,将其元类设为Singleton,那么创建类对象A时,行为发生如下:
A=Singleton(name,bases,class_dict),A其实为Singleton类的一个实例。
创建A的实例时,A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(),这样就将A的所有实例都指向了A的属性_instance上,这种方法与方法1其实是相同的。
方法4:使用模块
python中的模块module在程序中只被加载一次,本身就是单例的。可以直接写一个模块,将你需要的方法和属性,写在模块中当做函数和模块作用域的全局变量即可,根本不需要写类。
而且还有一些综合模块和类的优点的方法:
class_singleton(object):
classConstError(TypeError):
pass
def__setattr__(self,name,value):
ifnameinself.__dict__:
raiseself.ConstError
self.__dict__[name]=value
def__delattr__(self,name):
ifnameinself.__dict__:
raiseself.ConstError
raiseNameError
importsys
sys.modules[__name__]=_singleton()
python并不会对sys.modules进行检查以确保他们是模块对象,我们利用这一点将模块绑定向一个类对象,而且以后都会绑定向同一个对象了。
将代码存放在single.py中:
>>>importsingle
>>>single.a=1
>>>single.a=2
ConstError
>>>delsingle.a
ConstError
方法5:名字绑定法
最简单的方法:
classsingleton(object):
pass
singleton=singleton()
将名字singleton绑定到实例上,singleton就是它自己类的唯一对象了。
专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们
相关推荐
意法半导体VIPower全桥电机驱动器配备实时诊断功能简化车规电驱系统设计,降低系统成本
电子科技大学--嵌入式系统应用开发技术08
电子科技大学--嵌入式系统应用开发技术07
《嵌入式系统在计算机中应用》
KAUST:超宽禁带氧化镓晶相异质结
555构成的水位和排污控制器
畅连无限,创新赋能:罗德与施瓦茨亮相MWC 2025
《单片机开发与典型应用设计》
详谈碳化硅蚀刻工艺——干法蚀刻
L_OBJS的问题。
通过单芯片60GHz毫米波雷达传感器,降低车内传感的复杂性和成本
PCB设计中的“脖子设计”neck design
肖特集团2024财年逆势笃行,在挑战中稳健拓新
《农民运动讲习所》的免费字模软件
复旦大学在Si CMOS+GaN单片异质集成的探索
rc.疑问
电子科技大学--嵌入式系统应用开发技术06
请问:为何Arm板子上不能Ping通主机?
专业的工程师解答DSP问题
555构成的单相定量供电控制器
《单片机原理及应用》课程教学改革尝试
555构成的无塔增压供水装置液位控制电路
电子科技大学--嵌入式系统应用开发技术04
展望2025:人工智能将改变数据中心建设的方式
日本电装开发出GaN 三电平汽车电驱方案
多功能电子控制器(NE555、CD4022)
7月24日上海ARM网友聚会,欢迎大家光临
《单片机与嵌入式系统解决方案》
仿真自然风控制器
电子科技大学--嵌入式系统应用开发技术05