元類



元類

什麼是元類?
答:類的類。

如何理解?可以這樣說,我們用類來創建一個實例對象如myObject = MyClass()。事實上Python中的類也是對象(萬物皆對象),所以也需要通過類的類創建,如MyClass = MetaClass()。這個類的類(MetaClass)就是元類

元類從哪來

通常我們用type(object)來獲取一個對象的類型,如:

>>> type(512)
<class 'int'>
>>> type("zhong")
<class 'str'>

然而type()還有另一個用處:type(name, bases, dict) -> a new type,也就是用來創建一個類。一般我們都是通過class關鍵字來定義一個類:

class  MyClass(object):
	pass

但也可以用type動態創建一個類:

>>> MyClass = type("MyClass", (), {})
>>> myObject = MyClass()

其實type就是一個元類。Python中所有類都是通過type來創建的。我們可以通過__class__來驗證:

>>> str.__class__
<class 'type'>
>>> int.__class__
<class 'type'>
>>> object.__class__
<class 'type'>

我們自己用class定義出來的類也是如此:

>>> class MyClass(object):
	pass

>>> myObject = MyClass()
>>> myObject.__class__.__class__
<class 'type'>

type的用法

函數接口:type(name, bases, dict)

  • name:類名
  • bases:基類,接收一個元組
  • dict:綁定類的方法和屬性

現在通過類比的方式來理解type()的使用。

第一種:利用class關鍵字定義類

class MyClass(object):
    def __init__(self):
        self.string = "this is a test class"

    def print_str(self):
        print(self.string)

if __name__ == "__main__":
    myObject = MyClass()
    print(myObject.string)
    myObject.print_str()

# 輸出:
#this is a test class
#this is a test class

第二種:利用type創建類

string = "this is a test class"

def print_str(self):
    print(self.string)

MyClass = type(
               "MyClass",
               (object,),
               dict(string=string, print_str=print_str))

if __name__ == "__main__":
    myObject = MyClass()
    print(myObject.string)
    myObject.print_str()

# 輸出:
#this is a test class
#this is a test class

創建類的過程

當我們用如下方法

class MyClass(object):
	pass

Python做了這樣的操作:(1)在MyClass中尋找metaclass,如果存在,用它來創建名MyClass的類對象;(2)如果不存在,就去父類(這裏是object)中找;(3)最後都沒找到,利用Python內置的type()創建這個類對象

注: 在Python2中,如果沒在父類中找到metaclass會去模塊層次中尋找,但似乎Pythony3裏取消了,這裏留疑

metaclass的使用

比如,我們想給自己定義的類添加author屬性,即所有實例化的對象都可以執行語句:a.author來獲取作者信息,實現代碼如下:

def upper_attr(name, bases, attrs):
    # 增加author信息
    attrs.update({"author":"Guan"})
    # 返回一個類的類
    return type(name, bases, attrs)

# metaclass的使用方法
class MyClass(object, metaclass=upper_attr):
    pass


if  __name__ == "__main__":
    myObj = MyClass()
    print(myObj.author)

# 輸出:
#Guan

事實上,更建議metaclass對接一個自定義的元類,而不是函數

# 需要繼承自type
class MyMetaClass(type):
    def __new__(cls, name, bases, attrs):
        attrs.update({"author":"Guan"})
        return super().__new__(cls, name, bases, attrs)


class MyClass(object, metaclass=MyMetaClass):
    pass


if  __name__ == "__main__":
    myObj = MyClass()
    print(myObj.author)

# 輸出
#Guan

元類的作用

元類的主要目的就是爲了當創建類時能夠自動地改變類。正如我前邊的列子,創建的每一個類都能夠自動添加author屬性。

參考

  1. 伯樂在線(深刻理解Python中的元類(metaclass))
  2. 廖雪峯(使用元類)
  3. 知乎專欄(一步步理解Python中的元類metaclass)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章