1. 程式人生 > >《Python高階程式設計》(五)元類

《Python高階程式設計》(五)元類

元類

定義

物件例項化原理:物件例項化過程中會呼叫__new__和__init__方法建立新物件;作為物件的類本身也是另一種類的例項,用於建立類。
元類:負責生成其他類的類就是元類(Metaclass)

類與物件

:相當於一個模板,具有建立物件的能力
元類:在python中,一切皆物件,p1,p2,p3…都是物件。負責生成其他類的類就是元類(Metaclass)
python中,一切皆物件,包括函式和類。


Person類也是物件,那麼它由什麼類建立的呢?
通過type函式我們就知道這個物件p1是由哪個類創建出來的:

        >>> class Person:
            pass
        >>> p1 = Person()
        >>> p1
        <__main__.Person object at 0x022EB790>
        >>> type(p1)  #檢視p1是由哪個類建立的(Person)
        <class '__main__.Person'>
        >>> type(Person)  #檢視Persion類是由哪個類建立的(type)
		<class 'type'> 
		>>> type(type)
		<class 'type'>

總結:

  • type是Python的內建類,該類是其他類物件的預設類。它是建立其他類的預設元類
  • 可以使用Type而非使用Python關鍵字Class建立類。
  • type建構函式接受3個引數:
    • name:類的名稱
    • bases:該類的基類的元組
    • attrs:類中所以屬性的字典
  • type是Python中的主要元類。是其他元類的基類,也是元類層級的最高階

使用type建立類

實質:其實在python中,我們使用class建立類,當你使用class關鍵字時,Python直譯器自動建立這個物件。而底層其實使用的是type函式(type函式也可以檢視例項所屬型別)來建立類的。所以我們可以直接使用type()函式來手動實現動態建立類


使用Type建立類:

    def init(self, name):
    	self.name = name
    def eat(self):
        pass
    def go_to_vet(self):
        print "go_to_vet"
    Animal = type('Animal', (object,), {
        '__doc__': 'A class representing an arbitrary animal.',
        '__init__': init,
        'eat': eat,
        'go_to_vet': go_to_vet,
    })
    a = Animal('abc')
    print a.go_to_vet()

執行結果:
go_to_vet
None

解析:第二個引數是包含一個成員的元組:{object,}
表示:Animal類繼承於object

使用type建立繼承類:(繼承於Animal而不是object)

    def meow(self):
    	return None
    def purr(self):
        print "---purr---"
        return None
    Cat = type('Cat', (Animal,), {
        'meow':meow,
        'purr':purr,
    })
    c = Cat('cat')
    print c.purr()

檢視該物件是由什麼類建立的可以使用type:

    print type(c)
    print type(int):type類是基類,位於鏈的頂端,因此type(type)返回其自身
    print type(5)
    <class '__main__.Cat'>
    <type 'type'>
    <type 'int'>

object是所有類的基類,是類繼承鏈中的最高階
type也是元類層級的最高階

編寫元類

  • 只需要宣告一個繼承自type的類(使用class關鍵字)
  • 類只是物件,元類也只是類。元類的行為繼承自type;因此任何type的子類都可以作為元類
    class Meta(type):
    def __(cls, name, bases, attrs):
        return super(Meta, cls).____new____(cls, name, bases, attrs)

    C = Meta('C', (object,), {})
    print type(C)    #<class '__main__.Meta'>,即:該類是Meta的例項而不是type的例項
    #元類繼承
    class D(C):
        pass
    print type(D)       #<class '__main__.Meta'>
  • 可以看出,C的子類D也是Meta例項,而不是type的直接例項
  • 大多數情況下類只有一個元類。即使在多繼承的情況下,如果一個類的多個子類有不同的元類,python直譯器會檢查衝突。
    如果兩個元類的一個並不是另一個的直接子類,python直譯器會拒絕嘗試執行。(報出異常)

type建立類和class建立類的比較

摘自:https://blog.csdn.net/qq_26442553/article/details/82459234

  • 使用type建立帶屬性和方法的類
class Person(object):
    def __init__(self,name):
        self.name = name
    def p(self):
        print("這是Person的方法")
class Animal(object):
    def run(self):
        print("animal can run ")
#定義一個擁有繼承的類,繼承的效果和性質和class一樣。
Worker = type("Worker",(Person,Animal),{"job":"程式設計師"})
w1 = Worker("tom")
w1.p()
w1.run()
print(type(w1),type(Worker))
'''
這是Person的方法
animal can run 
<class '__main__.Worker'> <class 'type'>
<class '__main__.Person'>

總結:
- 通過type新增的屬性是類屬性,並不是例項屬性
通過type可以給類新增普通方法,靜態方法,類方法,效果跟class一樣
- type建立類的效果,包括繼承等的使用性質和class建立的類一樣。本質class建立類的本質就是用type建立。所以可以說python中所有類都是type建立的。

  • type定義帶繼承,屬性和方法的類

對元類理解

元類就是類的類,python中函式type實際上是一個元類。type就是Python在背後用來建立所有類的元類。Python中所有的東西——都是物件。這包括整數、字串、函式以及類。它們全部都是物件,而且它們都是從一個類建立而來,這個類就是type。type就是Python的內建元類,當然了,也可以建立自己的元類。

使用元類

  • python3中:通過呼叫Meta建立類C
        class C(metaclass=Meta):
            pass
  • python3中,將_metaclass_屬性賦給類:
        class C(object):
            __metaclass__ = Meta

何時使用元類

  • 大多數程式碼使用傳統的類與物件的結構都沒有問題,並不真的需要使用元類
  • 說明性類宣告,例如Django模型
  • 類驗證
  • 非繼承屬性

用的較少,以後再補充。