Python雖然是多範式的編程語言,但它的數據模型倒是 純面向對象 的。與那些僅在語法層面聲稱純OO的編程語言(如Java)相比,Python的這種純粹性更加深刻骨髓。html
在Python的世界裏,一切皆爲對象:數值、序列、字典、函數、模塊、文件、類、類實例 等等,無一例外(參考 Data model)。其中,「類也是對象」 的概念最讓人匪夷所思,這徹底超越了傳統的OO思想。python
元類(metaclass)是Python 2.2中引入的概念,利用元類能夠 定製類的建立行爲(Customizing class creation)。「元類」 的概念一樣讓人難以理解,然而理解 「元類」 是理解 「類也是對象」 的關鍵。編程
對於元類的理解,目前爲止,最經典的闡述莫過於Stack Overflow上面的這篇帖子 What is a metaclass in Python?,e-satis 神通常的回覆讓人醍醐灌頂,看完後基本就瞭然於胸了。markdown
若是以爲看英文比較吃力,這裏有一篇中文譯版 深入理解Python中的元類(metaclass)(注:英文原版最近有更新,但核心內容不變)。編程語言
對於類定義:函數
class Foo(Base): def say(self): print 'hello'
Python解釋器 執行class語句 時,處理步驟以下:code
肯定元類mcls
。元類的查找優先級爲:htm
__metaclass__
__metaclass__
__metaclass__
types.ClassType
;新式類:type
)使用元類mcls
建立類Foo
。建立語意等價於:對象
def say(self): print 'hello' # 元類的參數:mcls(name, bases, dict) Foo = mcls('Foo', (Base,), {'say': say})
建立成功後,類Foo
是 元類mcls
的 實例。blog
綜上:建立類 實際上是一種更高級別的 實例化過程,本質上與 建立類實例 類似。
實例化過程 | 類 | 實例 | 語意形式 |
---|---|---|---|
建立類Foo | 元類mcls | 類Foo | class Foo: pass <=> Foo = mcls('Foo', (), {}) |
建立類實例foo | 類Foo | 類實例foo | foo = Foo() |
原則上,元類能夠是:任何接受參數 name, bases, dict 並返回 類 的 可調用對象(參考 metaclass)。
例如元類能夠是 函數:
def metacls_func(name, bases, dict): # do customizing here return type(name, bases, dict)
根據最佳實踐指導,更好的習慣是使用 類 做爲元類,典型風格以下:
class MetaCls(type): def __new__(cls, name, bases, dict): # do customizing here return super(MetaCls, cls).__new__(cls, name, bases, dict)
注意:
__new__
,還能夠藉助__init__
和__call__
來定製被建立的類1)經典類(Classic classes)
類Old
的三種等價定義:
class Old: pass class Old: __metaclass__ = types.ClassType Old = types.ClassType('Old', (), {})
類Old
是元類types.ClassType
的實例:
>>> isinstance(Old, types.ClassType) True
2)新式類(New-style classes)
類New
的三種等價定義:
class New(object): pass class New: __metaclass__ = type New = type('New', (), {})
類New
是元類type
的實例:
>>> isinstance(New, type) True
爲全部類打上做者標籤:
class AuthorTag(type): def __new__(cls, name, bases, dict): dict['__author__'] = 'RussellLuo' return super(AuthorTag, cls).__new__(cls, name, bases, dict) class MyBlog: __metaclass__ = AuthorTag class MyGitHub: __metaclass__ = AuthorTag
如今,類MyBlog
和類MyGitHub
都免費得到了做者簽名:
>>> MyBlog.__author__ 'RussellLuo' >>> MyGitHub.__author__ 'RussellLuo'
請記住上面的簡單案例,若是您想從本文中得到對Python元類僅有的一點印象。紙上得來終覺淺,絕知此事要躬行,開始吧。