Python 深入理解元類 metaclass

2021-09-08 10:44:18 字數 4494 閱讀 8071

1.使用 type 動態建立類(type 是乙個類, 用來建立類物件的元類, 所以也可以繼承)

type("

person

", (), )

2.元類

python 中類也是物件, 元類就是建立這些類物件的類, 可以理解為

myclass =metaclass()

myobject = myclass()

3.type實際上是乙個元類, type就是python在背後用來建立所有類的元類, 類似 str 是建立字串物件的類, int 是建立整數的類, type 就是建立類的類

4.python 中所有東西都是物件!

>>> age = 35

>>> age.__class__

'int'>

>>> name = 'bob' >>> name.__class__ 'str'> >>> def foo(): pass >>>foo.__class__ 'function'> >>> class bar(object): pass >>> b =bar() >>> b.__class__

那麼對於任何乙個 __class__ 的 __class__ 屬性又是什麼呢?

>>> a.__class__.__class__

'type

'>

>>> age.__class__.__class__

'type

'>

>>> foo.__class__.__class__

'type

'>

>>> b.__class__.__class__

'type

'>

結論:元類就是建立類這種物件的東西, type就是python的內建元類(xx.__class__.__class__為 type )

5.__metaclass__ 屬性

可以在寫乙個類的時候為其新增 __metaclass__ 屬性

class

foo(object):

__metaclass__ =something…

pass

如果你這麼做了, python就會用元類來建立類foo, 小心點, 這裡面有些技巧,你首先寫下class foo(object), 但是類物件foo還沒有在記憶體中建立,

python會在類的定義中尋找__metaclass__屬性, 如果找到 了, python就會用它來建立類foo, 如果沒有找到, 就會用內建的type來建立這個類

6.深入理解下上一步中的 __metaclass__

class

foo(bar):

pass

foo中有__metaclass__這個屬性嗎?如果是, python會在記憶體中通過__metaclass__建立乙個名字為foo的類物件(我說的是類物件, 請緊跟我的思路), 如果python沒有找到__metaclass__, 它會繼續在bar(父類)中尋找__metaclass__ 屬性, 並嘗試做和前面同樣的操作, 如果python在任何父類中都找不到__metaclass__, 它就會在模組層次中去尋找 __metaclass__, 並嘗試做同樣的操作, 如果還是找不到__metaclass__, python就會用內建的type來建立這個類物件

現在的問題就是, 你可以在__metaclass__中放置些什麼**呢?答案就是: 可以建立乙個類物件的東西, 那麼什麼可以用來建立乙個類呢?type, 或者任何使用到type或者子類化type的東東都可以(像1中使用type建立類物件)

7.自定義元類

條件:模組裡所有的類的屬性都應該是大寫形式

實現(__metaclass__實際上可以被任意呼叫, 它並不需要一定是乙個正式的類):

#

元類會自動將你通常傳給『type』的引數作為自己的引數傳入

defupper_attr(future_class_name, future_class_parents, future_class_attr):

'''返回乙個類物件,將屬性都轉為大寫形式

'''#

選擇所有不以'__'開頭的屬性

attrs = ((name, value) for name, value in future_class_attr.items() if

not name.startswith('__'

))

#將它們轉為大寫形式

uppercase_attr = dict((name.upper(), value) for name, value in

attrs)

#通過'type'來做類物件的建立

return

type(future_class_name, future_class_parents, uppercase_attr)

__metaclass__ = upper_attr #

這會作用到這個模組中的所有類

class

foo(object):

#我們也可以只在這裡定義__metaclass__,這樣就只會作用於這個類中

bar = '

bip'

print hasattr(foo, '

bar')#

輸出: false

print hasattr(foo, '

bar')#

輸出:true

f =foo()

print

f.bar

#輸出:'bip'

用oop實現:

#

請記住,'type'實際上是乙個類,就像'str'和'int'一樣

#所以,你可以從type繼承

class

upperattrmetaclass(type):

#__new__ 是在__init__之前被呼叫的特殊方法

#__new__是用來建立物件並返回之的方法#而__init__只是用來將傳入的引數初始化給物件#你很少用到__new__,除非你希望能夠控制物件的建立#

這裡,建立的物件是類,我們希望能夠自定義它,所以我們這裡改寫__new__

#如果你希望的話,你也可以在__init__中做些事情

#還有一些高階的用法會涉及到改寫__call__特殊方法,但是我們這裡不用

def__new__

(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):

attrs = ((name, value) for name, value in future_class_attr.items() if

not name.startswith('__'

)) uppercase_attr = dict((name.upper(), value) for name, value in

attrs)

return type(future_class_name, future_class_parents, uppercase_attr)

8.為什麼要使用元類?

現在回到我們的大主題上來, 究竟是為什麼你會去使用這樣一種容易出錯且晦澀的特性?好吧, 一般來說, 你根本就用不上它:

「元類就是深度的魔法,99%的使用者應該根本不必為此操心。如果你想搞清楚究竟是否需要用到元類,那麼你就不需要它。那些實際用到元類的人都非常清楚地知道他們需要做什麼,而且根本不需要解釋為什麼要用元類。」  —— python界的領袖 tim peters

元類的主要用途是建立api, 乙個典型的例子是django orm, 它允許你像這樣定義:

class

person(models.model):

name = models.charfield(max_length=30)

age = models.integerfield()

但是如果你像這樣做的話:

guy  = person(name='

bob', age='35'

)print guy.age

這並不會返回乙個integerfield物件, 而是會返回乙個int, 甚至可以直接從資料庫中取出資料, 這是有可能的, 因為 models.model定義了__metaclass__, 並且使用了一些魔法能夠將你剛剛定義的簡單的person類轉變成對資料庫的乙個複雜hook, django框架將這些看起來很複雜的東西通過暴露出乙個簡單的使用元類的api將其化簡, 通過這個api重新建立**, 在背後完成真正的工作

9.小結

python中的一切都是物件, 它們要麼是類的例項, 要麼是元類的例項, 除了type, type實際上是它自己的元類

摘抄自:

深入理解Python類

c 中,類有兩個關鍵的內建函式,建構函式和析構函式。在python中,其實也有類似的函式,他們就是 def init self pass def del self pass def enter self pass def exit self pass在物件建立時執行操作。在物件析構時執行操作。注意 ...

深入理解python的類

如何解決這個問題 分析 這裡的windows繼承了qdockwidget,ui dockwidget 這就意味著,windows首先是乙個qdockwidget視窗,然後它還有ui dockwidget裡邊各種自定義的空間。在初始化的時候,首先呼叫父類的初始化方法 這裡ui dockwidget的這...

python 元類 python元類深入理解

1.python 中的類 在python中,類也是乙個物件,只不過這個物件擁有生成例項的能力,我們一般使用class 來定義乙個類,在python直譯器執行到這個地方的時候會自動建立出這個物件,python也為我們提供了手動建立類的方法,type type 這個方法對我們來說並不陌生,我們所熟知的用...