摘要:先簡單介紹下中的元類。元類就是創(chuàng)建類的類,對(duì)于元類來說,類是它的實(shí)例,將返回。中的所有類,都是的實(shí)例,換句話說,是元類的基類。
我在看源代碼的時(shí)候,經(jīng)常蹦出這一句:How does it work!竟然有這種操作?本系列文章,試圖剖析代碼中發(fā)生的魔法。順便作為自己的閱讀筆記,以作提高。
先簡單介紹下Python中的元類(metaclass)。元類就是創(chuàng)建類的類,對(duì)于元類來說,類是它的實(shí)例,isinstance(cls, metaclass)將返回True。Python中的所有類,都是type的實(shí)例,換句話說,type是元類的基類。使用type創(chuàng)建一個(gè)類的方法如下:
>>>type("MyClass", (), {})
注:使用type創(chuàng)建的類和使用元類的類,都是新式類
使用元類后,該類將由定義的元類實(shí)例化來創(chuàng)建。定義的方法在Python 2與Python 3中有所不同:
# Python 2: class MyClass(object): __metaclass__ = MyMeta # Python 3: class MyClass(metaclass=MyMeta): pass
如果你的項(xiàng)目需要兼容Python 2和Python 3,就需要使用一種方法,同時(shí)支持Python 2和Python 3。元類有兩個(gè)基本特性:
元類實(shí)例化得到類
元類能被子類繼承
根據(jù)這兩個(gè)特性,我們不難得到解決方案:
用元類實(shí)例化得到一個(gè)臨時(shí)類
定義類時(shí)繼承這個(gè)臨時(shí)類
我們可以寫出一個(gè)with_metaclass函數(shù):
def with_metaclass(meta, *bases): """Compatible metaclass :param meta: the metaclass :param *bases: base classes """ return meta("temp_class", bases, {}) # Testing: class TestMeta(type): def __new__(cls, name, bases, d): d["a"] = "xyz" return type.__new__(cls, name, bases, d) class Foo(object):pass class Bar(with_metaclass(TestMeta, Foo)): pass
我們就創(chuàng)建了一個(gè)以TestMeta為元類,繼承Foo的類Bar。驗(yàn)證:
>>> Bar.a "xyz" >>> Bar.__mro__ (, , , )
一切正常,但我們看到在Bar的mro里混進(jìn)了一個(gè)臨時(shí)類temp_class,你忽略它吧,有時(shí)會(huì)很麻煩。作為完美主義者,我想尋找一種解決辦法,不要在mro中引入多余的類。
Python的six模塊專門為解決Python 2to3兼容問題而生,模塊里帶有一個(gè)with_metaclass函數(shù),我們來看它是怎么實(shí)現(xiàn)的:(為了debug,添加了一個(gè)print語句)
def with_metaclass(meta, *bases): class metaclass(type): def __new__(cls, name, this_bases, d): print(cls, "new is called") return meta(name, bases, d) return type.__new__(metaclass, "temp_class", (), {}) # Testing: class TestMeta(type): def __new__(cls, name, bases, d): d["a"] = "xyz" print(cls, "new is called") return type.__new__(cls, name, bases, d)
一時(shí)看不懂?沒關(guān)系,我們來用用看,為了看清楚過程,我們分成兩步執(zhí)行:
>>> temp = with_metaclass(TestMeta, Foo) >>> class Bar(temp): pass ....metaclass"> new is called new is called >>> Bar.a "xyz" >>> Bar.__mro__ ( , , )
我們明明生成了一個(gè)臨時(shí)類temp_class,但后來竟然消失了!下面來仔細(xì)分析函數(shù)的運(yùn)行過程。首先我們看到,執(zhí)行第一步生成臨時(shí)類時(shí),兩個(gè)__new__都沒有調(diào)用,而第二步定義類時(shí),兩個(gè)__new__都調(diào)用了。奧秘就在函數(shù)的返回語句return type.__new__(metaclass, "temp_class", (), {}),它創(chuàng)建了一個(gè)臨時(shí)類,具有如下屬性:
名稱為temp_class
是函數(shù)內(nèi)部類metaclass的實(shí)例,它的元類是metaclass
沒有基類
創(chuàng)建時(shí)僅調(diào)用了type的__new__的方法
這是一個(gè)metaclass實(shí)例的不完全版本。接下來,定義Bar時(shí),Bar得到繼承的元類metaclass,過程如下:
實(shí)例化metaclass
調(diào)用metaclass.__new__
返回meta(name, bases, d), meta=TestMeta,bases=(Foo,)
調(diào)用TestMeta.__new__實(shí)例化得到Bar
Bar的基類由第3步得到,于是就去除了temp_class,這其實(shí)用到了閉包,with_metaclass返回的臨時(shí)類中,本身無任何屬性,但包含了元類和基類的所有信息,并在下一步定義類時(shí)將所有信息解包出來。
以上就是with_metaclass源代碼的解析,通過這篇文章,相信能加深元類與閉包的理解。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/41088.html
摘要:許多的頂尖研究人員都會(huì)積極的在現(xiàn)場(chǎng)回答問題。雖然有許多主題的常見問題頁面比如,這是一個(gè)機(jī)器學(xué)習(xí)的,但是這些都是非常不全面的,或者不夠精致。在這篇文章中,我試圖做一個(gè)更加全面的有關(guān)機(jī)器學(xué)習(xí)和問題的。 作者:chen_h微信號(hào) & QQ:862251340微信公眾號(hào):coderpai簡書地址:http://www.jianshu.com/p/ac18... showImg(https:/...
摘要:請(qǐng)注意,正斜杠位于結(jié)束標(biāo)記中的標(biāo)記描述之前。正斜杠必須在所有結(jié)束標(biāo)簽之前,但標(biāo)簽的語言必須與開頭標(biāo)簽相同,上面的示例是。無論元素是否包含值,只要使用兩個(gè)標(biāo)簽,開始和關(guān)閉標(biāo)簽必須完全匹配,精確到大小寫除了結(jié)束標(biāo)簽中的正斜杠。 By Rob Sheldon, 2014/03/26 (首次發(fā)表于: 2012/09/20) 關(guān)于系列 本文屬于進(jìn)階系列:XML進(jìn)階 自2003年以來,XML一直是...
摘要:編程語言及面向?qū)ο蠡A(chǔ)題 編程語言及面向?qū)ο蠡A(chǔ)題 Design Pattern What is singleton? Whats its cons and pros? How to implement it?Definition: Singleton pattern is a design pattern that ensure that only one instance of a...
摘要:本文僅用于學(xué)習(xí)和交流目的,不得用于商業(yè)目的。今年,我們依然會(huì)組織。隨著語言的發(fā)展,這種情況將不再適用。本系列主要討論如何獲得這些高度模塊化的應(yīng)用程序。這一系列內(nèi)的后續(xù)圖書會(huì)討論測(cè)試及部署等內(nèi)容。更多精彩,加入圖靈訪談微信 本文僅用于學(xué)習(xí)和交流目的,不得用于商業(yè)目的。非商業(yè)轉(zhuǎn)載請(qǐng)注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/art... 訪談...
閱讀 1703·2021-09-26 09:55
閱讀 1448·2021-09-23 11:22
閱讀 2813·2021-09-06 15:02
閱讀 2713·2021-09-01 11:43
閱讀 4084·2021-08-27 13:10
閱讀 3751·2021-08-12 13:24
閱讀 2127·2019-08-30 12:56
閱讀 3059·2019-08-30 11:22