<rp id="wnpn7"><ruby id="wnpn7"></ruby></rp>
<progress id="wnpn7"><track id="wnpn7"><rt id="wnpn7"></rt></track></progress>
<ruby id="wnpn7"></ruby>
<ruby id="wnpn7"><blockquote id="wnpn7"><div id="wnpn7"></div></blockquote></ruby>

    1. <em id="wnpn7"><ruby id="wnpn7"><input id="wnpn7"></input></ruby></em>
      1. <button id="wnpn7"><acronym id="wnpn7"></acronym></button><button id="wnpn7"><acronym id="wnpn7"></acronym></button>

        <rp id="wnpn7"><acronym id="wnpn7"></acronym></rp>

        <li id="wnpn7"><object id="wnpn7"><u id="wnpn7"></u></object></li>
        VB.net 2010 視頻教程 VB.net 2010 視頻教程 python基礎視頻教程
        SQL Server 2008 視頻教程 c#入門經典教程 Visual Basic從門到精通視頻教程
        當前位置:
        首頁 > 編程開發 > 簡明python教程 >
        • 簡明python教程之類和對象的創建過程(元類,__new__,__init__,__call__)

        本站最新發布   Python從入門到精通|Python基礎教程
        試聽地址  
        http://www.squ68.com/eschool/python.html


        一、 type()

        1、創建類的兩種方式

        方式一

         

        我們創建了一個名為MyClass的類,并實例化了這個類,得到其對象myc

        上面代碼打印的結果為:

        type()函數可以查看一個類型或變量的類型,MyClass是一個class,它的類型就是type,而myc是一個實例,它的類型就是class MyClass。

        我們說class的定義是運行時動態創建的,而創建class的方法就是使用type()函數。

        type()函數既可以返回一個對象的類型,又可以創建出新的類型,比如,我們可以通過type()函數創建出MyClass類,而無需通過Class MyClass(object)...的定義:

        方式二

        動態創建類

        type(類名, 父類的元組(針對繼承的情況,可以為空),包含屬性的字典(名稱和值))

        打印結果:

         

        要創建一個class對象,type()函數依次傳入3個參數:

        class的名稱;

        繼承的父類集合,注意Python支持多重繼承,如果只有一個父類,別忘了tuple的單元素寫法;

        class的方法名稱與函數綁定,這里我們把函數fn綁定到方法名func上。

        通過type()函數創建的類和直接寫class是完全一樣的,因為Python解釋器遇到class定義時,僅僅是掃描一下class定義的語法,然后調用type()函數創建出class。

        type就是創建類對象的類。你可以通過檢查__class__屬性來看到這一點。Python中所有的東西,注意,我是指所有的東西——都是對象。這包括整數、字符串、函數以及類。它們全部都是對象,而且它們都是從一個類(元類,默認為type,也可以自定制)創建而來。type也是由type創建。。

        二、元類(metaclass)

        除了使用type()動態創建類以外,要控制類的創建行為,還可以使用metaclass。

        metaclass,直譯為元類,簡單的解釋就是:

        當我們定義了類以后,就可以根據這個類創建出實例,所以:先定義類,然后創建實例。

        但是如果我們想創建出類呢?那就必須根據metaclass創建出類,所以:先定義元類(不自定義時,默認用type),然后創建類。

        連接起來就是:先定義metaclass,就可以創建類,最后創建實例。

        所以,metaclass允許你創建類或者修改類。換句話說,你可以把類看成是元類創建出來的“實例”。

        默認情況下,類是使用type()構造的。類主體在一個新的名稱空間中執行,類名在本地綁定到類型的結果(名稱、基、名稱空間)。

        可以通過在類定義行中傳遞元類關鍵字參數來定制類創建過程,或者從包含此類參數的現有類繼承。在下面的示例中,MyClass和MySubclass都是Meta的實例:

         

        使用metaclass的兩種方式

        方式一:即用類的形式

        執行代碼后,當遇到class Foo時即聲明要創建一個Foo類,就會調用type的__init__方法創建類,由于此處(metaclass=MyType),即指定了Foo類的創建方式,所以會執行type的派生類MyType的__init__方法,創建Foo類,打印一次'xx'

        *一般情況下, 如果你要用類來實現metaclass的話,該類需要繼承于type,而且通常會重寫type的__new__方法來控制創建過程。

        * 在metaclass里面定義的方法會成為類的方法,可以直接通過類名來調用

        方式二:用函數的形式

        構建一個函數,返回一個type的派生類對象,例如叫type的派生類, 需要3個參數:name, bases, attrs

        • name: 類的名字
        • bases: 基類,通常是tuple類型
        • attrs: dict類型,就是類的屬性或者函數

        metaclass 原理

        1.基礎

        metaclass的原理其實是這樣的:當定義好類之后,創建類的時候其實是調用了type的__new__方法為這個類分配內存空間,創建好了之后再調用type的__init__方法初始化(做一些賦值等)。所以metaclass的所有magic其實就在于這個__new__方法里面了。

        說說這個方法:__new__(cls, name, bases, attrs)

        cls: 將要創建的類,類似與self,但是self指向的是instance,而這里cls指向的是class

        name: 類的名字,也就是我們通常用類名.__name__獲取的。

        bases: 基類

        attrs: 屬性的dict。dict的內容可以是變量(類屬性),也可以是函數(類方法)。

        所以在創建類的過程,我們可以在這個函數里面修改name,bases,attrs的值來自由的達到我們的功能。這里常用的配合方法是

        getattr和setattr(just an advice)

        2.查找順序

        元類是由以下優先規則決定的:

        如果“元類”存在,它就被使用了。

        否則,如果至少有一個基類,則使用它的元類(這首先查找類屬性,如果沒有找到,則使用它的類型)。

        否則,如果一個名為元類的全局變量存在,就會使用它。

        三、 __init__,__new__,__call__三個特殊方法

        __new__: 對象的創建,是一個靜態方法,第一個參數是cls。(想想也是,不可能是self,對象還沒創建,哪來的self)

        其必須要有返回值,返回實例化出來的實例,需要注意的是,可以return父類__new__()出來的實例,也可以直接將object的__new__()出來的實例返回。

        __init__ : 對象的初始化, 是一個實例方法,第一個參數是self,該self參數就是__new__()返回的實例,__init__()在__new__()的基礎上可以完成一些其它初始化的動作,__init__()不需要返回值。

        __call__ : 對象可call,注意不是類,是對象。

        1.對于__new__

        打印結果為:

        <__main__.Bar object at 0x0090F930>

        可以看到,輸出來是一個Bar對象。

        __new__方法在類定義中不是必須寫的,如果沒定義,默認會調用object.__new__去創建一個對象。如果定義了,就是會覆蓋,使用自定義的,這樣就可以自定制創建對象的行為。

        單例模式也可以通過這種方式來創建。

        2.對于__init__

        打印結果:

        __init__ 方法通常用在初始化一個類實例的時候,但__init__其實不是實例化一個類的時候第一個被調用 的方法。當使用 Persion(name, age) 這樣的表達式來實例化一個類時,最先被調用的方法 其實是 __new__ 方法。從打印結果就可以看出來

        若__new__()沒有正確返回當前類cls的實例,那__init__()將不會被調用,即使是父類的實例也不行。

        3.對于__call__

        對象通過提供__call__(slef, *args ,**kwargs)方法可以模擬函數的行為,如果一個對象x提供了該方法,就可以像函數一樣使用它,也就是說x(arg1, arg2...) 等同于調用x.__call__(self, arg1, arg2) 。

        4、實例化對象的完整過程

        當我們寫如這段代碼時,Python做了如下的操作:

        Foo中有metaclass這個屬性嗎?如果是,Python會在內存中通過metaclass創建一個名字為Foo的類對象(我說的是類對象,請緊跟我的思路)。如果Python沒有找到metaclass,它會繼續在Bar(父類)中尋找metaclass屬性,并嘗試做和前面同樣的操作。如果Python在任何父類中都找不到metaclass,它就會在模塊層次中去尋找metaclass,并嘗試做同樣的操作。如果還是找不到metaclass,Python就會用內置的type來創建這個類對象。

        把上面這段話反復讀幾次,現在的問題就是,你可以在metaclass中放置些什么代碼呢?

        答案就是:可以創建一個類的東西。

        那么什么可以用來創建一個類呢?

        type,或者任何使用到type或者子類化type的東東都可以。

        以上面的代碼為例,我們實例化一個對象obj=Foo()時,會先執行Foo類的__new__方法,沒寫時,用父類的__new__方法,創建一個對象,并返回,然后執行__init__方法(自己有就用自己的,沒有就用父類的),對創建的對象進行初始化。

        obj()會執行Foo類的__call__方法,沒有則用父類的

        我們現在已經知道,類也是對象,是元類的對象,即我們實例化一個類時,調用其元類的__call__方法。

        元類處理過程:定義一個類時,使用聲明或者默認的元類對該類進行創建,對元類求type運算,得到父元類(該類聲明的元類的父元類),調用父元類的__call__函數,在父元類的__call__函數中, 調用該類聲明的元類的__new__函數來創建對象(該函數需要返回一個對象(指類)實例),然后再調用該元類的__init__初始化該對象(此處對象是指類,因為是元類創建的對象),最終返回該類

        1.對象是類創建,創建對象時候類的__init__方法自動執行,對象()執行類的 __call__ 方法

        2.類是type創建,創建類時候type的__init__方法自動執行,類() 執行type的 __call__方法(類的__new__方法,類的__init__方法)

        原始type的__call__應該是參數結構應該是
        
          metaname, clsname, baseclasses, attrs
        
         
        
        原始type的__new__
        
          metaname, clsname, baseclasses, attrs
        
         
        
        原始type的__init__
        
          class_obj, clsname, baseclasses, attrs
        
         
        
        元類的__new__和__init__影響的是創建類對象的行為,父元類的__call__控制對子元類的 __new____init__的調用,就是說控制類對象的創建和初始化。父元類的__new__和__init__由更上層的控制
        
            一般來說,原始type是最初的父元類,其__new__和__init__是具有普遍意義的,即應該是分配內存、初始化相關信息等
        
        元類__call__影響的是創建類的實例對象的行為,此時如果類自定義了__new__和__init__就可以控制類的對象實例的創建和初始化
        
         
        
        __new__和__init__ 影響的是創建對象的行為,當這些函數在元類中時,影響創建的是類;同理,當這倆個函數在普通類中時,影響創建的是普通的對象實例。
        
        __call__ 影響()調用行為, __call__是在創建類的時候調用,即: class Test(object): __metaclass__=type, 定義類時就是創建類,此時會調用元類的__call__,如果元類有繼承,子元類定義時執行的是父元類的__call__
        
                     如果是普通類實例化對象,調用的是普通類的__call__

        轉自:類和對象的創建過程(元類,__new__,__init__,__call__)

        相關教程
                
        免费看成年人视频大全_免费看成年人视频在线观看