Python基礎:元類

1、概述

Python雖然是多範式的編程語言,但它的數據模型倒是 純面向對象 的。與那些僅在語法層面聲稱純OO的編程語言(如Java)相比,Python的這種純粹性更加深刻骨髓。html

在Python的世界裏,一切皆爲對象:數值序列字典函數模塊文件類實例 等等,無一例外(參考 Data model)。其中,「類也是對象」 的概念最讓人匪夷所思,這徹底超越了傳統的OO思想。python

元類(metaclass)是Python 2.2中引入的概念,利用元類能夠 定製類的建立行爲Customizing class creation)。「元類」 的概念一樣讓人難以理解,然而理解 「元類」 是理解 「類也是對象」 的關鍵。編程

2、經典闡述

對於元類的理解,目前爲止,最經典的闡述莫過於Stack Overflow上面的這篇帖子 What is a metaclass in Python?,e-satis 神通常的回覆讓人醍醐灌頂,看完後基本就瞭然於胸了。markdown

若是以爲看英文比較吃力,這裏有一篇中文譯版 深入理解Python中的元類(metaclass)(注:英文原版最近有更新,但核心內容不變)。編程語言

3、核心總結

一、類的建立過程

對於類定義:函數

class Foo(Base):
    def say(self):
        print 'hello'

Python解釋器 執行class語句 時,處理步驟以下:code

  1. 肯定元類mcls。元類的查找優先級爲:htm

    • 首先查找 類Foo 是否擁有屬性__metaclass__
    • 不然查找 類Foo的父類 是否具備屬性__metaclass__
    • 不然查找 類Foo所在模塊 是否具備全局變量__metaclass__
    • 不然使用默認元類(經典類:types.ClassType;新式類:type
  2. 使用元類mcls建立類Foo。建立語意等價於:對象

    def say(self):
        print 'hello'
    
    # 元類的參數:mcls(name, bases, dict)
    Foo = mcls('Foo', (Base,), {'say': say})
  3. 建立成功後,類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__來定製被建立的類

4、簡單案例

一、默認行爲

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'

5、實踐爲王

請記住上面的簡單案例,若是您想從本文中得到對Python元類僅有的一點印象。紙上得來終覺淺,絕知此事要躬行,開始吧。

相關文章
相關標籤/搜索