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