Python中的元類和 metaclass

2022-04-06 12:23:59 字數 4558 閱讀 8835

1.什麼是元類

元類讓你來定義某些類是如何被建立的,從根本上說,賦予你如何建立類的控制權。可以把元類想成是乙個類中類,或是乙個類,它的例項是其它的類。當某個類呼叫type()函式時,你就會看到它到底是誰的例項。

>>> class c(object):

pass

>>> class cc:

pass

>>> type(c)

>>> type(cc)

>>> import types

>>> type(cc) is types.classtype

true

2.什麼時候使用元類

元類一般用於建立類。在執行類定義時,將檢查此類正確的元類,元類通常傳遞三個引數:類名、從基類繼承資料的元組和類的屬性字典。

使用class語句定義新類時,直譯器執行類的整個主體並填充字典。一旦字典填充完畢,就會被傳遞給元類建構函式,以建立相應的類物件。

在執行類定義時,直譯器必須要知道這個類的正確的元類。

首先,類可以顯式地指定其元類,這通過設定__metaclass__類變數來實現:

class foo:

__metaclass__ = type

在python3中,使用下面的語法(在基類元組中提供metaclass關鍵字引數):

class foo(metaclass=type)

如果沒有顯式指定元類,class語句將檢查基類元組(如果存在)中的第乙個條目。在這種情況下,元類與第乙個基類的型別相同。所以,在編寫以下內容時,foo的類型別將與object相同。

class foo(object):pass

如果沒有指定基類,class語句將檢查全域性變數__metaclass__是否存在。如果找到了該變數,將使用它來建立類。

__metaclass__ = type

class foo:

pass

最後,如果沒有找到任何__metaclass__值,python將使用預設的元類。在python2中,預設的元類是types.classtype(舊樣式類),在python3中,預設的元類就是type()。

3.誰在使用元類

元類的終端使用者不是使用者,正是程式設計師自己。你可以通過定義乙個元類來「迫使」程式設計師按照某種方式實現目標類,這既可以簡化他們的工作,也可以使所編寫的程式更符合特定標準。

4.元類何時被建立

建立的元類用於改變類的預設行為和建立方式。建立乙個新風格的類或傳統類的做法是使用系統自己所提供的元類的預設方式。

自定義元類時,它通常會繼承自type(),並重新實現__init__()或__new__()方法。

5.技巧

顯式選擇元類的最常用技巧是首先定義乙個基類,該基類然後用作要被歸檔的所有物件的父類。例如:

class documented:

__metaclass__ = docmeta#docmeta是已定義的基類

在python3中,使用下面的語法(在基類元組中提供metaclass關鍵字引數):

class documented(metaclass=docmeta)

class foo(documented):

spam(self,a,b):

'spam does something'

pass

元類示例1:用元類建立類時,顯示時間標籤:

from time import ctime

print '***welcome to metaclasses!'

print '\tmetaclasses declaration first.'

class metac(type):

def __init__(cls,name,bases,attrd):

super(metac,cls).__init__(name,bases,attrd)

print '***created class %r at: %s' % (name,ctime())

print '\tclass "foo" declaration next.'

class foo(object):

__metaclass__ = metac

def __init__(self):

print '***instantiated class %r at: %s' %(self.__class__.__name__,ctime())

print '\tclass "foo" instantiation next.'

f = foo()

print '\tdone'

執行後輸出:

***welcome to metaclasses!

metaclasses declaration first.

class "foo" declaration next.

***created class 'foo' at: thu may 30 11:22:35 2013

class "foo" instantiation next.

***instantiated class 'foo' at: thu may 30 11:22:35 2013

done

元類示例2:建立乙個元類,要求程式設計師在他們寫的類中提供乙個__str__()方法的實現。如果你還沒有在類中覆蓋__repr__()方法,元類會給出警告,提示你這麼做。如果未實現__str__()方法,將引發乙個typeerror的異常。

from  warnings import warn

class reqstrsugrepr(type):

def __init__(cls,name,bases,attrd):

super(reqstrsugrepr,cls).__init__(name,bases,attrd)

if '__str__' not in attrd:

raise typeerror('class requires overriding of __str__()')

if '__repr__' not in attrd:

warn('class suggests overriding of __repr__()\n',stacklevel = 3)

print '***defined reqstrsugrepr (meta)class\n'

class foo(object):

__metaclass__ = reqstrsugrepr

def __str__(self):

return 'instance of class:',self.__class__.__name__

def __repr__(self):

return self.__class__.__name__

print '***defined foo class\n'

class bar(object):

__metaclass__ = reqstrsugrepr

def __str__(self):

return 'instance of class:',self.__class__.__name__

print '***defined bar class\n'

class foobar(object):

__metaclass__ = reqstrsugrepr

print '***defined foobar class\n'

我們編寫了三個關於元類的示例,其中乙個(foo)過載了特殊方法__str__()和__repr__(),另乙個(bar)只實現了特殊方法__str__(),還有乙個都沒有實現,這種情況是錯誤的。執行此指令碼後,我們得到如下輸出:

***defined reqstrsugrepr (meta)class

***defined foo class

warning (from warnings module):

file "c:\python27\lib\idlelib\run.py", line 298

exec code in self.locals

userwarning: class suggests overriding of __repr__()

***defined bar class

traceback (most recent call last):

file "c:\documents and settings\administrator\桌面\meta.py", line 29, in

class foobar(object):

file "c:\documents and settings\administrator\桌面\meta.py", line 7, in __init__

raise typeerror('class requires overriding of __str__()')

typeerror: class requires overriding of __str__()

需要注意的是我們並沒有建立任何測試類的例項,這些類本身就是元類的例項。

python中的元類

python中的元類大家都可能比較很陌生,因為大家都聽說過99 的情況下是用不到元類的,但是大家對類確很了解,大家都知道在python中萬物皆物件,那麼python中的類是不是物件呢?物件的樣子 1,物件可以在程式中動態的進行建立,python的語言動態特性。2,物件可以通過 class 獲取該物件...

Python 中的元類

如果看完以後還是感覺莫名其妙,執行這樣乙個demo 可能會對你有所幫助 元類程式設計在我看來,如果你想開發一些框架,可以嘗試一下 class upperattrmetaclass type type dict def new cls,cls name,bases,attr dict news cls...

python中的元類

目錄其他 我們建立乙個類目的是為了建立該類的例項物件,而元類就是用來建立類的。換個理解方式就是,元類就是建立類的類。在python中可以使用type函式建立乙個類,參考 python中type的用法 用法如下 tpye name,bases,dict 實際上type 函式就是乙個元類,是python...