最初博主是但願在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
咱們來慢慢分析。
以上就是我對元類的理解,其中若有錯誤的地方還請你們斧正。