详解python单例模式与metaclass
单例模式的实现方式
将类实例绑定到类变量上
classSingleton(object): _instance=None def__new__(cls,*args): ifnotisinstance(cls._instance,cls): cls._instance=super(Singleton,cls).__new__(cls,*args) returncls._instance
但是子类在继承后可以重写__new__以失去单例特性
classD(Singleton): def__new__(cls,*args): returnsuper(D,cls).__new__(cls,*args)
使用装饰器实现
defsingleton(_cls): inst={} defgetinstance(*args,**kwargs): if_clsnotininst: inst[_cls]=_cls(*args,**kwargs) returninst[_cls] returngetinstance @singleton classMyClass(object): pass
问题是这样装饰以后返回的不是类而是函数,当然你可以singleton里定义一个类来解决问题,但这样就显得很麻烦了
使用__metaclass__,这个方式最推荐
classSingleton(type): _inst={} def__call__(cls,*args,**kwargs): ifclsnotincls._inst: cls._inst[cls]=super(Singleton,cls).__call__(*args) returncls._inst[cls] classMyClass(object): __metaclass__=Singleton
metaclass
元类就是用来创建类的东西,可以简单把元类称为“类工厂”,类是元类的实例。type就是Python的内建元类,type也是自己的元类,任何一个类
>>>type(MyClass) type >>>type(type) type
python在创建类MyClass的过程中,会在类的定义中寻找__metaclass__,如果存在则用其创建类MyClass,否则使用内建的type来创建类。对于类有继承的情况,如果当前类没有找到,会继续在父类中寻找__metaclass__,直到所有父类中都没有找到才使用type创建类。
如果模块里有__metaclass__的全局变量的话,其中的类都将以其为元类,亲自试了,没这个作用,无任何影响
查看type的定义,
type(object)->theobject'stype
type(name,bases,dict)->anewtype
所以利用type定义一个类的元类,可以用函数返回一个上面第二种定义的对象,也可以继承type并重写其中的方法。
直接使用type生成的对象作为元类,函数作用是使属性变为大写
defupdate_(name,bases,dct): attrs=((name,value)forname,valueindct.items()ifnotname.startswith('__')) uppercase_attr={name.upper():valueforname,valueinattrs} returntype(name,bases,uppercase_attr) classSingleton(object): __metaclass__=update_ abc=2 d=Singleton() printd.ABC #2
上一节中,单例模式元类实现用的是类继承方式,而对于第一种__new__的方式,本质上调用的是type.__new__,不过使用super能使继承更清晰一些并避免一些问题
这里简单说明一下,__new__是在__init__前调用的方法,会创建对象并返回,而__init__则是用传入的参数将对象初始化。看一下type中这两者以及__call__的实现
def__init__(cls,what,bases=None,dict=None):#knownspecialcaseoftype.__init__ """ type(object)->theobject'stype type(name,bases,dict)->anewtype #(copiedfromclassdoc) """ pass @staticmethod#knowncaseof__new__ def__new__(S,*more):#realsignatureunknown;restoredfrom__doc__ """T.__new__(S,...)->anewobjectwithtypeS,asubtypeofT""" pass def__call__(self,*more):#realsignatureunknown;restoredfrom__doc__ """x.__call__(...)<==>x(...)""" pass
前面提到类相当于元类的实例化,再联系创建单例模式时使用的函数,用的是__call__,其实用三种magicmethod中任何一种都是可以的,来看一下使用元类时各方法的调用情况
classBasic(type): def__new__(cls,name,bases,newattrs): print"new:%r%r%r%r"%(cls,name,bases,newattrs) returnsuper(Basic,cls).__new__(cls,name,bases,newattrs) def__call__(self,*args): print"call:%r%r"%(self,args) returnsuper(Basic,self).__call__(*args) def__init__(cls,name,bases,newattrs): print"init:%r%r%r%r"%(cls,name,bases,newattrs) super(Basic,cls).__init__(name,bases,dict) classFoo: __metaclass__=Basic def__init__(self,*args,**kw): print"init:%r%r%r"%(self,args,kw) a=Foo('a') b=Foo('b')
结果
new:<class'__main__.Basic'>'Foo'(){'__module__':'__main__','__metaclass__':<class'__main__.Basic'>,'__init__':<functioninitat0x106fd5320>} init:<class'__main__.Foo'>'Foo'(){'__module__':'__main__','__metaclass__':<class'__main__.Basic'>,'__init__':<functioninitat0x106fd5320>} call:<class'__main__.Foo'>('a',) init:<__main__.Fooobjectat0x106fee990>('a',){} call:<class'__main__.Foo'>('b',) init:<__main__.Fooobjectat0x106feea50>('b',){}
元类的__init__和__new__只在创建类Foo调用了一次,而创建Foo的实例时,每次都会调用元类的__call__方法
以上就是本文的全部内容,对python单例模式与metaclass进行了描述,希望对大家的学习有所帮助。