扣丁学堂Python视频教程之创建单例模式五种方法
2017-12-27 10:17:04
504浏览
今天扣丁学堂给大家介绍一下关于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就是它自己类的唯一对象了。
以上就是关于扣丁学堂Python视频教程之创建单例模式五种方法的详细介绍,最后想要了解更多资讯或学习Python开发请关注扣丁学堂官网和微信公众号。扣丁学堂作为知名的IT培训机构,不仅有专业的Python培训讲师和与时俱进的课程体系,还有大量的Python全栈开发工程师视频教程供学员观看学习,想要学好Python开发技术的小伙伴就抓紧时间行动吧。扣丁学堂Python技术交流群:279521237。
【关注微信公众号获取更多学习资料】
标签:
Python视频教程
Python基础教程
Python爬虫
Python培训
Python在线视频