python元類程式設計

2021-10-07 05:25:45 字數 3941 閱讀 7930

當我們希望動態的產生類的時候,就需要用到元類程式設計的手段。要掌握此技術,需要明白以下幾個基本內容:

metaclass

type

__new__

__call__

在python 中,所有東西都是物件(object),包括python的類(class),也是乙個物件。檢視乙個物件的類,可以用物件的__class__屬性

class

foo(

object):

defhello

(self)

:print

('hello'

)f=foo(

)print

(f.__class__)

#=> __main__.foo

print

(foo.__class__)

#==> type

從上面執行結果可以看到,foo的類是type。所以『類』的初始化是由 「type類」來做。

type是乙個python內建類,所以看不到**,但可看到定義:

class

type

(object):

def__call__

(self,

*args,

**kwargs)

:# real signature unknown

pass

def__init__

(cls, what, bases=

none

,dict

=none):

# known special case of type.__init__

pass

@staticmethod

# known case of __new__

def__new__

(*args,

**kwargs)

:# real signature unknown

pass

#省略其它部分

type 有兩種用法,一是查詢某個物件的類:

#type(object) -> the object's type,e.g.

type

("string"

)# ==>out[2]: str

另乙個則是用來產生乙個類,傳入三個引數: 類名,基類,屬性與方法字典:

# type(class_name, bases, attrs) ,e.g.

deffn

(self)

:print

("hello"

)foo=

type

("foo",(

object,)

,)f=foo(

)f.hello(

)#=> hello

python 直譯器執行時,發現上述class foo的定義後,其實就是翻譯成:

foo=

type

("foo",(

object,)

,)

元類就是用來產生類的類,通過以上講解,應該明白type類就是乙個元類。

我們還可以繼承type類,用自定義的元類可做到:

影響類的定義過程,比如為類自動增加一些方法和屬性

影響定義出來的類的例項化過程,比如為該類的每個例項都做些特殊處理

例子:

class

metabase

(type):

def__new__

(mcs, name, bases=

none

, attrs=

none):

print

('1.建立類時,先呼叫__new__,分配定義類所需的記憶體'

)return

super()

.__new__(mcs, name, bases, attrs)

def__init__

(cls, what, bases=

none

, attrs=

none):

print

('2:然後,呼叫__init__,完成定義'

)return

super()

.__init__(what, bases, attrs)

def__call__

(cls,

*args,

**kwargs)

:print

('例項化定義後的類時,會呼叫__call__'

)return

super()

.__call__(

*args,

**kwargs)

deffn

(self, name=

'world'):

print

('hello {}'

% name)

definit_fn

(self)

:print

('init_fn'

)aclass = metabase(

"aclass",(

object,)

,dict

(hello=fn, __init__=init_fn)

)a = aclass(

)

執行結果:

1.建立類時,先呼叫__new__,分配定義類所需的記憶體

2:然後,呼叫__init__,完成定義

例項化定義後的類時,會呼叫__call__

init_fn

為講清楚上面的例子的執行結果,需要講一下兩個魔法函式:__new__ 與 __call__

python 物件在例項化的第一步,是分配記憶體,分配記憶體就是__new__的責任。為type子類的例項分配記憶體的事,只能由 type.__new__來幹,所以上述例子中最後呼叫的是type.__new__ ,該函式返回的是乙個分配好記憶體的例項,該函式的四個引數分別是:類,名稱,基類,屬性

def

__new__

(mcs, name, bases=

none

, attrs=

none

):

在乙個類上定義了__call__方法後,該類的例項就可當作函式來呼叫

class

callableobject()

:def

__call__

(self)

:print

("hello, i'm like a function!"

)fn = callableobject(

)fn(

)

執行結果

hello, i'm like a function!
在之前的類子中,因為aclass 的類是metabase, 而betabase定義了__call__,所以當建立aclass例項時,列印出了

例項化定義後的類時,會呼叫__call__
在python 3.7 中,可以在申明類的時候,指定 metaclass

class

foo(

object

,metaclass=metabase)

:def

hello

(self)

:print

('hello'

)

在python2 中,是寫成:

class

foo(

object):

__metaclass__= metabase

defhello

(self)

:print

('hello'

)

python 元類程式設計

裝飾器任何時候你定義裝飾器的時候,都應該使用 functools 庫中的 wraps 裝飾器來註解底層包裝函式.因為乙個普通裝飾器作用在某個函式上時,這個函式的重要的元資訊比如名字 文件字串 註解和引數簽名都會丟失。但是 wraps不會。import time from functools impo...

python 元類程式設計

getattr 方法可用來檢查乙個類中是否有乙個屬性,比如 class user def init self,name self.name name def getattr self,item print not find attr def main user user dog user.age i...

Python類元程式設計

類元程式設計是指動態地建立或定製類,也就是在執行時根據不同的條件生成符合要求的類,一般來說,類元程式設計的主要方式有類工廠函式,類裝飾器和元類。通常,我們都是使用 class 關鍵字來宣告乙個類,像這樣 class a name a 但是,我們還有另外一種方式來生成類,下述 與上面作用相同 a ty...