python单例模式的多种实现方法
前言
单例模式(SingletonPattern),是一种软件设计模式,是类只能实例化一个对象,
目的是便于外界的访问,节约系统资源,如果希望系统中只有一个对象可以访问,就用单例模式,
显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
在Python中,我们可以用多种方法来实现单例模式:
- 使用模块
- 使用__new__
- 使用装饰器(decorator)
- 使用元类(metaclass)
概念
简单说,单例模式(也叫单件模式)的作用就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个(当然也可以不存在)
例子:
一台计算机上可以连好几个打印机,但是这个计算机上的打印程序只能有一个,这里就可以通过单例模式来避免两个打印作业同时输出到打印机中,即在整个的打印过程中我只有一个打印程序的实例。
super(B,self).__init__()是这样理解的:super(B,self)首先找到B的父类(就是类A),然后把类B的对象self转换为类A的对象(通过某种方式,一直没有考究是什么方式,惭愧),然后“被转换”的类A对象调用自己的__init__函数。考虑到super中只有指明子类的机制,因此,在多继承的类定义中,通常我们保留使用类似代码段1的方法。
1.super并不是一个函数,是一个类名,形如super(B,self)事实上调用了super类的初始化函数,
产生了一个super对象;
2.super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
3.super(B,self).func的调用并不是用于调用当前类的父类的func函数;
4.Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数
只调用一次(如果每个类都使用super);
5.混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一
个父类函数被调用多次。
__new__:对象的创建,是一个静态方法,第一个参数是cls。(想想也是,不可能是self,对象还没创建,哪来的self)
__init__:对象的初始化,是一个实例方法,第一个参数是self。
__new__方法在类定义中不是必须写的,如果没定义,默认会调用object.__new__去创建一个对象。如果定义了,就是override,可以custom创建对象的行为。
聪明的读者可能想到,既然__new__可以custom对象的创建,那我在这里做一下手脚,每次创建对象都返回同一个,那不就是单例模式了吗?没错,就是这样。可以观摩《飘逸的python-单例模式乱弹》
定义单例模式时,因为自定义的__new__重载了父类的__new__,所以要自己显式调用父类的__new__,即object.__new__(cls,*args,**kwargs),或者用super()。,不然就不是extend原来的实例了,而是替换原来的实例。
代码
importthreading classSignleton(object): def__init__(self): print("__init__methodcalled") def__new__(cls): print("__new__methodcalled") mutex=threading.Lock() mutex.acquire()#上锁,防止多线程下出问题 ifnothasattr(cls,'instance'): cls.instance=super(LogSignleton,cls).__new__(cls) mutex.release() returncls.instance if__name__=='__main__': obj=Signleton()
输出结果:
>>>================================RESTART================================ >>> __new__methodcalled __init__methodcalled >>>
说明
1.从输出结果来看,最先调用__new__方法,然后调用__init__方法
2.__new__通常用于控制生成一个新实例的过程,它是类级别的方法。
3.__init__通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性,做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
方法1
__new__在__init__初始化前,就已经实例化对象,可以利用这个方法实现单例模式。
print'----------------------方法1--------------------------' #方法1,实现__new__方法 #并在将一个类的实例绑定到类变量_instance上, #如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回 #如果cls._instance不为None,直接返回cls._instance classSingleton(object): def__new__(cls,*args,**kw): ifnothasattr(cls,'_instance'): orig=super(Singleton,cls) cls._instance=orig.__new__(cls,*args,**kw) returncls._instance classMyClass(Singleton): a=1 one=MyClass() two=MyClass() two.a=3 printone.a #3 #one和two完全相同,可以用id(),==,is检测 printid(one) #29097904 printid(two) #29097904 printone==two #True printoneistwo #True
方法2
print'----------------------方法2--------------------------' #方法2,共享属性;所谓单例就是所有引用(实例、对象)拥有相同的状态(属性)和行为(方法) #同一个类的所有实例天然拥有相同的行为(方法), #只需要保证同一个类的所有实例具有相同的状态(属性)即可 #所有实例共享属性的最简单最直接的方法就是__dict__属性指向(引用)同一个字典(dict) #可参看:http://code.activestate.com/recipes/66531/ classBorg(object): _state={} def__new__(cls,*args,**kw): ob=super(Borg,cls).__new__(cls,*args,**kw) ob.__dict__=cls._state returnob classMyClass2(Borg): a=1 one=MyClass2() two=MyClass2() #one和two是两个不同的对象,id,==,is对比结果可看出 two.a=3 printone.a #3 printid(one) #28873680 printid(two) #28873712 printone==two #False printoneistwo #False #但是one和two具有相同的(同一个__dict__属性),见: printid(one.__dict__) #30104000 printid(two.__dict__) #30104000
方法3
print'----------------------方法3--------------------------' #方法3:本质上是方法1的升级(或者说高级)版 #使用__metaclass__(元类)的高级python用法 classSingleton2(type): def__init__(cls,name,bases,dict): super(Singleton2,cls).__init__(name,bases,dict) cls._instance=None def__call__(cls,*args,**kw): ifcls._instanceisNone: cls._instance=super(Singleton2,cls).__call__(*args,**kw) returncls._instance classMyClass3(object): __metaclass__=Singleton2 one=MyClass3() two=MyClass3() two.a=3 printone.a #3 printid(one) #31495472 printid(two) #31495472 printone==two #True printoneistwo #True
方法4
print'----------------------方法4--------------------------' #方法4:也是方法1的升级(高级)版本, #使用装饰器(decorator), #这是一种更pythonic,更elegant的方法, #单例类本身根本不知道自己是单例的,因为他本身(自己的代码)并不是单例的 defsingleton(cls,*args,**kw): instances={} def_singleton(): ifclsnotininstances: instances[cls]=cls(*args,**kw) returninstances[cls] return_singleton @singleton classMyClass4(object): a=1 def__init__(self,x=0): self.x=x one=MyClass4() two=MyClass4() two.a=3 printone.a #3 printid(one) #29660784 printid(two) #29660784 printone==two #True printoneistwo #True one.x=1 printone.x #1 printtwo.x
单例模式
单例模式(SingletonPattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个AppConfig的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建AppConfig对象的实例,这就导致系统中存在多个AppConfig的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似AppConfig这样的类,我们希望在程序运行期间只存在一个实例对象。
在Python中,我们可以用多种方法来实现单例模式:
- 使用模块
- 使用__new__
- 使用装饰器(decorator)
- 使用元类(metaclass)
使用模块
其实,Python的模块就是天然的单例模式,因为模块在第一次导入时,会生成.pyc文件,当第二次导入时,就会直接加载.pyc文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:
#mysingleton.py classMy_Singleton(object): deffoo(self): pass my_singleton=My_Singleton()
将上面的代码保存在文件mysingleton.py中,然后这样使用:
frommysingletonimportmy_singleton my_singleton.foo()
使用__new__
为了使类只能出现一个实例,我们可以使用__new__来控制实例的创建过程,代码如下:
classSingleton(object): _instance=None def__new__(cls,*args,**kw): ifnotcls._instance: cls._instance=super(Singleton,cls).__new__(cls,*args,**kw) returncls._instance classMyClass(Singleton): a=1
在上面的代码中,我们将类的实例和一个类变量_instance关联起来,如果cls._instance为None则创建实例,否则直接返回cls._instance。
执行情况如下:
>>>one=MyClass() >>>two=MyClass() >>>one==two True >>>oneistwo True >>>id(one),id(two) (4303862608,4303862608)
使用装饰器
我们知道,装饰器(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]。
使用metaclass
元类(metaclass)可以控制类的创建过程,它主要做三件事:
- 拦截类的创建
- 修改类的定义
- 返回修改后的类
使用元类实现单例模式的代码如下:
classSingleton(type): _instances={} def__call__(cls,*args,**kwargs): ifclsnotincls._instances: cls._instances[cls]=super(Singleton,cls).__call__(*args,**kwargs) returncls._instances[cls] #Python2 classMyClass(object): __metaclass__=Singleton #Python3 #classMyClass(metaclass=Singleton): #pass
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。