1. 程式人生 > >2019新年快樂 - 學習python的“元類”

2019新年快樂 - 學習python的“元類”

1學習的原文:What are metaclasses in Python

時刻牢記:python是面向物件的,才能理解python的“元類”

    理解python元類的概念之前,一定要時刻牢記python是面向物件的,也就是說,python中,一切都是物件,整數是物件、字串是物件、函式也是物件,類的例項更是物件。

>>> age = 47
>>> type(age)
<class 'int'>
>>> age.__class__
<class 'int'>
>>> city =
'shenyang' >>> city.__class__ <class 'str'> >>> type(city) <class 'str'> >>>

    python中,類(class)也是物件!

class ObjectCreator(object):
...   pass

    當python直譯器看到定義類的關鍵字“class”時,在記憶體中建立一個名稱為類名(ObjectCreator)的“物件”,這個物件(類)自身能建立一個物件(這個類的例項),因此這也就證明了這個“物件”就是個“類”。而且因為這個 “類”同時也是個物件,所以這個物件(類)可以:
        - 被賦值給一個變數
        - 可以複製(copy)
        - 可以給它增加屬性
        - 可以作為一個函式的引數被傳遞
        - 類的定義程式碼不一定非得寫在“外面”,它可以寫在函式內部!
    上面這段話有些繞嘴,但它是理解“元類”這個概念的基礎:python中的類不僅僅是一段定義類的程式碼,它本身就是存在於記憶體中的一個物件,這個物件可以被用來建立其它的類(子類)。

>>> def choose_class(name):
...     if name == 'foo':
...             class Foo(object):
...                     pass
...             return Foo #return the class, not an instance
...     else:
...             class Bar(object):
...                     pass
...             return Bar
...
>>> MyClass = choose_class('foo') >>> print (MyClass) <class '__main__.choose_class.<locals>.Foo'> >>> MyClass = choose_class('bar') >>> print (MyClass) <class '__main__.choose_class.<locals>.Bar'> >>> print (MyClass()) <__main__.choose_class.<locals>.Bar object at 0x108dea4e0>

    那麼,問題是:既然類是物件,那誰來建立這個物件?這個物件有沒有父類?
    答案是:type產生類!
    “type”函式除了能返回“物件”的“類”型之外。還是python用來動態產生“類”的函式。語法如下:

type(name of the class,
     tuple of the parent class (for inheritance, can be empty),
     dictionary containing attributes names and values)

    例如,下面這個類,通常的定義是:

>>> class MyShinyClass(object):
...       pass

    使用type而不是上面的程式碼產生MyShinyClass類的方法如下:

>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print (MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x108dea2e8>
>>> 

    也就是說,python直譯器將類定義的程式碼動態的用type在記憶體中生成一個物件。

元類 metaclass

    閱讀如上所述的python建立類的過程可以得出結論:“類”也是個物件,那這個物件肯定是某個類的例項(物件),而這個“某個類”就是所謂的“元類(metaclass)”,也就是說,元類是所有類的類,是所有類的“父類”,這個元類(metaclass)就是“type”!“type”就是python的內嵌的“元類(metaclass)”!

>>> age = 45
>>> age.__class__
<class 'int'>
>>> name = 'bob'
>>> name.__class__
<class 'str'>
>>> def foo(): pass
... 
>>> foo.__class__
<class 'function'>
>>> class Bar(object): pass
... 
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
>>> age.__class__.__class__
<class 'type'>
>>> name.__class__.__class__
<class 'type'>
>>> foo.__class__.__class__
<class 'type'>
>>> b.__class__.__class__
<class 'type'>
>>> 

    看到了吧,type就是python所有物件(類)的“元類”,它定義了python所有類(內建或自定義)建立時所需做的預設操作,也正是因為這樣,python中可以自定義“元類”。

建立自己的元類

    建立自己的元類的目的,是增加一些“在類建立時的預設操作”。
    python2中自定義元類的程式碼:

class Foo(object):
	__metaclass__ = something...

    這個something可以是anything,通常是一個完成特定功能的函式。
python3中自定義元類的程式碼:

class Foo (object, metaclass = something):
	[...]

注意:
原文中有這麼一段話:
Be careful here that the metaclass attribute will not be inherited, the metaclass of the parent (Bar.class) will be. If Bar used a metaclass attribute that created Bar with type() (and not type.new()), the subclasses will not inherit that behavior.
這段話字面意思是:__metaclass__這個,“特性”是不能被繼承的,能被繼承的是這個類的父類的元類。這句話也有些“混沌”,大概的意思就是:__metaclass__不是一個公開的可以被子類繼承的“屬性”,它只是這個“類”用來實現自定義“元類”的一種實現手段。或者乾脆這麼理解:__metaclass__不是面向物件程式設計概念中的“屬性(property)”,是父類的私有特性。


  1. What are metaclasses in Python? ↩︎