python 元類

來源:互聯網
上載者:User

標籤:檢查   類載入   ret   做了   meta   *args   type   erro   python3.6   

python 元類

之前想清楚了寫到了筆記中,最近看到python3.6又出了個__init_subclass__,之前的東西又全忘了.這次在總結一下.

new: 結合javascript的原型鏈體會一下動態語言一切皆對象的思想.

以一個實用的執行個體
#!/usr/bin/env pythonclass Type(object):    print("運行到", "Type")    def __init__(self, type_):        print("set type", type_)        self.type_class = type_    def vaild(self, value):        return isinstance(value, self.type_class)class TypeCheckMeta(type):    print("運行到", "TypeCheckMeta")    def __new__(cls, name, bases, dict):        print("元類 __new__")        inst = super(TypeCheckMeta, cls).__new__(cls, name, bases, dict)        inst._fileds = {}        for k, v in dict.items():            if isinstance(v, Type):                inst._fileds.setdefault(k, v)        return inst    def __init__(cls, *args, **kwargs):        print("元類 __init__")        super(TypeCheckMeta, cls).__init__(*args, **kwargs)    def __call__(self, *args, **kwargs):        print("元類 __call__")        return super(TypeCheckMeta, self).__call__(*args, **kwargs)class Test(metaclass=TypeCheckMeta):    print("運行到", "Test")    name = Type(str)    age = Type(int)    def __new__(cls, *args, **kwargs):        print("類 __new__")        print(args, kwargs)        return super(Test, cls).__new__(cls)    def __setattr__(self, key, value):        print("類 __setattr__")        if key in self._fileds:            if not self._fileds[key].vaild(value):                raise TypeError("invaild...")        super(Test, self).__setattr__(key, value)    def __init__(self, a):        print("類 __init__")    def __call__(self, *args, **kwargs):        print("類 __call__")t = Test(1)print(t)

  

情境就是需要你對變數做強制性檢查.

載入過程

注釋掉最後兩行代碼,會發現如下輸出

運行到 Type運行到 TypeCheckMeta運行到 Testset type <class ‘str‘>set type <class ‘int‘>元類 __new__元類 __init__

  

首先,Python在載入的時候掃過整個檔案.遇到類定義的時候如下執行:

  1. 解析類中的元素, 建立類變數與方法, 並載入到類空間中. 類的基類資訊, 元類等資訊.
  2. 找到該類的元類,然後調用元類的__new__方法,參數是(類名where,類基類bases,類空間dict)
  3. 元類的__new__最終一定會調用內建類型type.__new__
  4. type.__new__會調用元類的__init__建立出一個類對象放在記憶體中.至此類對象已經載入完成了.
執行過程

現在我們來看看執行的

t = Test(1)print(t)
  1. Test是什麼?從文法層面上,他是一個類.但是在執行過程中,經過上面的載入步驟,它是一個產生的執行個體,所以Test()會調用元類的__call__方法.
  2. 元類一定又得陷入type.__call__方法.
  3. type.__call__方法調用類__new__方法.
  4. 類的__new__方法一定又陷入object.__new__
  5. object.__new__調用類的__init__方法,最終一個執行個體被建立出來了.
新的方法 __init_subclass__(self, k=...)

觸發時機: 子類載入時觸發.
具體的: 載入子類時發現父類定義了__init_subclass__方法,那麼在元類__new__之後__init__之前調用這個__init_subclass__.(實現應該不是這樣子的,應該是基於回調.比如在type這個元元元類基礎上檢測調用__init_subclass__).

這樣就不需要寫元類就可以修飾子類了.

其傳參數方式並沒有什麼魔法,

class SubClass(Father, param="haha"):    pass

  

在傳遞給__new__的時候給現在要多一個位置參數

def __new__(cls, name, bases, dict, **kwargs):    pass

  

這樣子__init_subclass__也可以擷取到了.

動態語言–一切都是對象
function People(name) {    this.name = name}p = new People("Irn")

  

不瞭解js原型鏈的同學會很疑惑這種寫法.很明顯通過關鍵詞function表明了People是個函數,那麼,new 函數算什麼文法?
實際上js裡的函數可不僅僅是一個c語言層面的函數,他是一個完整的執行個體,是Function建立出來的執行個體.

f = new Function(‘name‘, ‘return alert("hello, " + name + "!");‘);

這樣我們就有一個constructor的對象,他們可以使用new關鍵詞.
在建立一個對象的時候,解譯器做了如下工作:

  1. It creates a new object.
  2. It sets the constructor property of the object to Vehicle.
  3. It sets up the object to delegate to Vehicle.prototype.
  4. It calls Vehicle() in the context of the new object.

具體的看參考網上的說明!

其中在設定prototype的時候完成了類變數,類函數的繼承.
最後一步調用函數的.prototype.call(第一步建立出來的Null 物件),這個時候函數的this參數就會指向這個新的對象,這樣就會擁有執行個體變數(每個人都不一樣的)
所以最合理的類比類實現是這個樣子的

// Class definition / constructorvar Vehicle = function Vehicle(color) {  // Initialization  this.color = color;}// Instance methodsVehicle.prototype = {  go: function go() {    return "Vroom!";  }}

  

prototype裡的東西所有的變數都共用一份,在執行個體裡找不到就會向上尋找,而function這個構造器裡的this因為指向的是一個{}每次執行都會重新賦值一遍,而且會屏蔽在prototype上設定的屬性.

this和prototype是js裡非常聰明的做法也是整個的基石.

python 元類

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.