准備
在Python中,一切皆對象。
既然一切皆對象,那么類也是對象,我們暫且稱之為 類對象。來個簡單例子(本篇文章的所有案例都是運行在Python3.4中):
class foo(): pass print(id(foo)) print(type(foo)) # 結果: # 46627056 # <class 'type'>
如果想深入了解一下,可以看:深刻理解Python中的元類(metaclass)
引入
最近在閱讀tornado源碼,發現在其源碼中有很多類是這樣的:
class HTTPServer(TCPServer, Configurable, httputil.HTTPServerConnectionDelegate): def __init__(self, *args, **kwargs): # Ignore args to __init__; real initialization belongs in # initialize since we're Configurable. 就是說默認的__init__初始化方法不在起作用了,改為了initialize方法進行初始化 pass
或者是干脆沒有__init__ ,只寫了個initialize方法來替代。
所以心生疑惑,tornado是如何做到這一點的?
正題
接下來我們來了解一下,Python解釋器是如何創建對象的。
大家可能對Python中的__init__方法很熟悉,認為他是實例化類時調用的第一個方法。但其實他並不是。實例化時調用的第一個方法其實是__new__方法。
好了,接下來是重點:
1 當我們實例化A類對象時,Python中首先調用的是該A類對象的__new__方法,如果該A類對象沒有定義__new__方法,則去父類中依次查找,直到object類
2 object類有一個__new__方法,該方法接收一個參數(一般為類對象),將該參數進行實例化並返回一個對象
3 Python解釋器會將調用__new__方法並將A類對象作為第一個參數傳入,最后會返回一個對象(這個對象就是A類的實例對象,我們稱之為a1)
4 Python解釋器默認會調用a1對象的__init__方法,並將參數傳入。
來一個例子驗證一下:
class asd(object): def __new__(cls, *args, **kwargs): print('asd.__new__() is running. cls id is %s'%id(cls)) r = super(asd,cls).__new__(cls) print('r_id is %s'%id(r)) return r class bnm(asd): def __init__(self,name): print('bnm.__init__() is running, self id is %s'%id(self)) self.name = name print('bnm.name is %s'%(self.name)) print('asd_id is %s'%id(asd)) print('bnm_id is %s'%id(bnm)) o1 = bnm('ni') print('o1_id is',id(o1)) # asd_id is 49838320 # bnm_id is 49838768 # asd.__new__() is running. cls id is 49838768 # r_id is 49848400 # bnm.__init__() is running, self id is 49848400 # bnm.name is ni # o1_id is 49848400
注意 : bnm 和 cls 是同一個對象! r 和 o1 也是同一個對象 !
應用
仿tornado實現自定義類的初始化方法:

class asd(object): def __new__(cls, *args, **kwargs): r = super(asd,cls).__new__(cls) r.initialize(*args) return r class bnm(asd): def initialize(self): print('bnm_initialize is running') class foo(asd): def initialize(self,name): self.name = name print('foo_initialize is running, my name is %s' %(self.name)) r = bnm() r1 = foo('linghuchong') # bnm_initialize is running # foo_initialize is running, my name is linghuchong
定義類時,只要繼承了asd類,就會將initialize方法作為初始化方法,是不是感覺很(wu)酷(lun)炫(yong)?