最初博主是但愿在python当中建立一个单列模式的类,由于python当中不像java和php当中有权限修饰符(private),因此实现起来要绕一点。php
网上找了一下python实现单列模式,相似的大概有这种方法:java
class singleton(type): """ 实现单列模式的元类 总之,metaclass的主要任务是: 拦截类, 修改类, 返回类 """ def __init__(cls,classname,parrentstuple,attrdict): """ """ super(SigleInstance,cls).__init__(classname,parrentstuple,attrdict) cls._instance = None def __call__(self,*args,**kargs): """ """ if self._instance: return self._instance else: self._instance = super(SigleInstance,self).__call__(*args,**kargs) return self._instance
这就是单列的元类,我把它小写了,由于type也是小写的。而后呢,在即将要实现单列的class当中这样写:python
class Earth(object): __metaclass__ = singleton def __init__(self,a,b): pass
这样每次 建立一个 Earth()取得的始终都应该是一个实例。python2.7
关于__metaclass__ 和type这个东西能够参考深刻理解Python中的元类(metaclass)。这篇文章解决了我大部分的疑惑,可是我仍是没有搞清楚的是:函数
当__metaclass__是一个类的时候,metaclass是怎样去建立一个类的?spa
在这以前首先说明一下:.net
一。python当中一切都是对象,而对象都是由类建立,这里为了区分概念,咱们不妨换一种说法:实例都是由模板建立的。code
二。那么什么又是对象的type呢?type就是类型的意思。若是您对java稍微有一点了解。你会有这样的认识:htm
/** * language是一个String类型的变量,值为"python" * 在java当中,若是 Integer language = "python"就是错误的 */ String language = "python";
因为python是一门动态语言(变量无类型,变量的值才有类型),python当中变量的值同样是有类型的。那么怎么来看变量值的类型呢?答案是使用type。对象
language = "python" print type(language) # python2.7中输出:<type 'str'> # ipython 输出 str number = 2 print type(number) #输出:<type 'int'> class A(object): pass a = A() print type(a) #输出:<type '__main__.A'>
上面段代码分别用type查看到了各个变量的类型。根据(一)【python当中一切都是对象,而对象都是由类建立,这里为了区分概念,咱们不妨换一种说法:实例都是由模板建立的】咱们可不能够这样说呢:language是str的实例,str是language实例的模板。所以type(a_var)的输出就是a_var这个实例的模板。因此咱们看到 type(a)的输出是<type '__main__.A'>,也就是说 a实例的模板是A。
class A的模板是什么呢?
print type(A) #输出:<type 'type'>
也就是说,一个类的模板的type,类是type的一个实例,tpye实例化了一个对象,这个对象就是class。因此在python的世界里,一切都是对象,类也是对象。
那么有意思的地方来了,type的模板是什么呢,也就是,type的type是什么呢?
print type(type) # 输出<type 'type'>
是否是颇有意思,type的type是type。很绕,换成大白话说:type的模板是type本身。那么是否是就能够这样说呢?TYPE(type,为了区分说明,故意大写)是type的模板,type是TYPE的实例,所以说明type是一个实例;而TYPE是一个模板,也就是一个类!,由于TYPE==type,那么能够得出结论:
type是一个类(class),type也是自身的实例(instance)
python当中一切都是对象,类也是对象,对于type来讲,更为特殊,由于type的模板是type,也就是说,type本身建立了本身,type是自身的实例。
三。实例是由类模板建立(也就是咱们平时所写的class),而类是由元类模板建立(就是__metaclass__指定的类)。因此【元类和类的关系】就相似于【实例和类的关系】。
根据博主所探讨的结果代表,__metaclass__在建立类的过程大概是这样的:当类Earth的实例 earth正要被建立的时候,
查找Earth当中是否有__metaclass__,若是没有查找父类是否有__metaclass__,若是没有找到,就看包当中是否有__metaclass__,若是仍是没有,那直接使用type建立该类。若是找到了,就用该__metaclass__来建立类。
那么若是找了__metaclass__,那么系统首先建立一个__metaclass__的实例,而这个由metaclass建立的实例正好的一个 Earth类,注意是Earth类(class),而不是一个Earth的一个实例哦。
那么到这一步究竟发生了些什么呢?咱们写几行代码来看一看:
#!/usr/bin/env python #-*-coding:utf-8-*- # author : "qiulimao" # email : "qiulimao@getqiu.com" """ the module's duty """ #---------- code begins below ------- class SimpleMetaClass(type): def __init__(self,*args,**kwargs): print "you have create a class instance by metaclass" super(SimpleMetaClass,self).__init__(*args,**kwargs) class Earth(object): __metaclass__ = SimpleMetaClass def sayHello(): print "hello world" if __name__ == "__main__": print "do something that have nothing with SimpleMetaClass and Earth"
最后运行的结果是这样的:
you have create a class instance by metaclass #① do something that have nothing with SimpleMetaClass and Earth #②
经过这个小例子咱们看到:咱们并无使用过 Earth类,也没有使用过SimpleMetaClass这个元类,但实际的结果看来,SimpleMetaClass这个模板确被使用过了,由于打印出了①,后面咱们会知道,打印出①是由于python使用SimpleMetaClass模板来建立出了Earth这个类对象(不是Earth的一个实例)。这个过程咱们能够用咱们日常常常说的一句话来描述:这个步骤至关于实例化了一个metaclass(SimpleMetaClass)对象,而这个对象正好是Earth类。
那么这里确定会有人问了:我平时写class的时候都是不带__metaclass__的啊?那是由于若是你不写__metaclass__,最终这个类的模板就是type。上面的代码能够看到SimpleMetaClass是继承自type的。
四。Earth类已经被metaclass所建立出来了,那么当实例化一个Earth类(也就是建立一个earth对象)的时候又发生了什么呢?
在说明这个问题以前,咱们得先聊一聊__call__,__new__这两个特殊方法。对于一个实现了__call__的类,那么它的实例能够当作函数来调用。来看个例子:
class MagicCall(object): def __new__(cls,name): return super(MagicCall,cls).__new__(cls) def __init__(self,name): self.name=name def __call__(self): print "you have invoked __call__ method...." if __name__ == '__main__': magicCall = MagicCall("python") magicCall() #输出的结果为:you have invoked __call__ method....
而__new__有拦截类实例化的功能,在建立一个对象的过程当中,执行__init__方法时,解释器已经为对象分配了内存,实例已经存在了,__init__方法只是改变这个类当中的某些参数。而在执行__new__方法时,这个实例是不存在的,而__new__就是要建立这个实例,因此__new__必需要有返回值。
如今咱们回过头来想想:为何建立 一个类的实例是这种写法:
instance = SomeClass() instance = SomeClass(args1,args2,...)
回答这个问题,咱们能够用元类来解释。咱们知道类是元类的一个对象,而元类的实例都有一个__call__方法。拥有__call__方法的对象能够把对象当作一个函数调用。因此喽,咱们在建立一个类的实例的时候,其实是调用了类对象的__call__(MetaClass:__call__)这个方法。
来看一个比较长的例子:
#!/usr/bin/env python #-*-coding:utf-8-*- # author : "qiulimao" # email : "qiulimao@getqiu.com" """ the module's duty """ #---------- code begins below ------- class SimpleMetaClass(type): def __new__(cls,*args,**kwargs): print "creating class Earth..." return super(SimpleMetaClass,cls).__new__(cls,*args,**kwargs) def __init__(self,*args,**kwargs): print "you have create a class instance by metaclass" super(SimpleMetaClass,self).__init__(*args,**kwargs) def __call__(self,*args,**kwargs): print "__call__ in metaclass has been invoked...","the args:",args,kwargs return super(SimpleMetaClass,self).__call__(*args,**kwargs) class Earth(object): __metaclass__ = SimpleMetaClass def __new__(cls,g,R=65535): print "creating instance using __new__" cls.g = g cls.R = R return super(Earth,cls).__new__(cls); def __init__(self,g,R=65535): print "initializing instance in __init__" print "gravity on Earth is:%f" % self.g def __call__(self): print self.g def sayHello(self): print "hello earth,your gravity is:%f" % self.g if __name__ == "__main__": earth = Earth(9.8,R=65535) earth() earth.sayHello()
不知道大众喜欢在代码中写注释的方式来说解,仍是直接写文字过程。我就写文字过程吧。
最终上面这段代码执行的结果是:
①creating class Earth... ②you have create a class instance by metaclass ③__call__ in metaclass has been invoked... the args: (9.8,) {'R': 65535} ④creating instance using __new__ ⑤initializing instance in __init__ ⑥gravity on Earth is:9.800000 ⑦9.8 ⑧hello earth,your gravity is:9.800000
咱们来慢慢分析。
以上就是我对元类的理解,其中若有错误的地方还请你们斧正。