Python魔法方法(在合適的時間,python自動調用如下方法魔法方法)


此前我們已經解除了Python中最常用的魔法方法:__init__

什么時候調用__init__? 答:我們想在對象實例化的時候就賦某些值就重寫它唄!就是看需求,有需要就重寫,沒需要就不重寫唄,不重寫就是啥也沒有唄!嗯~對的!

 

*__init__(self[,...])

  __init__是不可以設置返回值的,他只能默認的返回None,如果試圖給它設置返回值,會出現TypeError的異常

 

 *__new__(cls[,...])

  實際上實例化一個類的時候第一個調用的不是__init__方法,而是這個__new__方法

  ·他和其他實例化方法不同,他的第一個參數是類和self一樣就寫cls,如果后面有參數,后面的參數會原封不動的傳給__init__方法

  ·__new__返回一個實例對象,可以是這個類的實例對象也可以是其他類的實例對象

  ·一般情況下我們極少的會去重寫這個__new__方法

 

  ·但是在繼承了不可改變的父類的時候,new方法就顯得尤為重要了

   因為init只能返回None,因此我們設置這個new去掉用不可改變的父類中的方法,如下我想把所有的字符串都變成大寫顯示

  我發現這樣寫也行[但是上方那樣還寫,只修改了傳入的string,而其他的str方法繼續用,而下方的可能就沒了把,不太清楚,如果用還是按照上方那樣用]

 

   實際上通過__init__方法也可以實現,只不過不能直接返回,而是通過函數調用出來,但是他不調用方法,實例化返回的還是aaa,而new實例化返回的就是我們所設定好的全部大寫了!!,可見還是有很大區別的。

         

 

 *__del__(self)

  當對象【內存】被銷毀的時候,這個方法會被自動的調用

 

  他是當垃圾回收機制回收的時候,他才會調用這個對象的del方法,因此下圖等號不成了(並不是我們調用del方法,他就會調用__del__方法)

 

 

 

           工廠函數

     ~~~算數運算~~~~【個人覺得這東西知道怎么用即可,隨着學習的深入可能以后會用到】

 

   當你調用加法是會自動調用__add__方法,調用減法的時候會自動調用__sub__方法...

 

  但是注意了,下圖這樣會報錯【報錯的原因是無線遞歸,因為self是實例化對象,other是執行方法是另一個參數對象,而self是由這個類實例化的,因此當執行到(return self + other)的時候,會調用__add__方法,如此一直調用,停不下來!】

         

  解決方法:將self轉化成int,不當成這個類的對象,則不會調用該類的__add__方法了

  

 

 

 什么是反運算呢?

如a+b,而a沒有__add__方法,則會執行b的__radd__方法:

如下圖:數字1沒有__add__方法,因此會執行a對象中的的__radd__方法 #如果倆個都是數字沒有,個人理解是默認是int,但是這個int優先級比Nint低,為什么呢?因為Nint繼承自int,而int內置方法沒有寫出來,優先級比較低,直接寫出來的radd方法優先級高。  先這樣寫看看以后怎么說!!!

下圖中在(1+a)中調用radd方法的self指的就是a對象,而other才是1

     

         增量賦值運算

 

             簡單定制

 

 

 

 

 *__str__(self)

  #print這個實例化對象走的就是__str__()

 

 *__repr__(self)

  #沒有重新定於__new__方法,實例化對象直接返回的就是__repr__()

#調用new是最強的,有它在實例化后返回的一定是new返回的,如果沒有它,則是repr返回的 #Nxj自己測試的結果 【但是new還是很少用的嘛,還是需要多看多練加強記憶別搞混】

  

 

 

 

localtime()返回的的是如下的元組結構:

其實寫的有問題,就是比如說開始時間是是16:25:50 結束時間是16:26:04 ,那么返回的是個負數

解決思路應該是如果是負數說明最起碼最前面的第一項一定大【16:26:50~~17:22:05】【如果不全部化成秒的話】,如果發現這個是負數,就用60+上這個負數返回,相應的需要把end的數組這個的前一項數值-1 ,對於分鍾也是這樣,而對於小時就是+12 了,一直到年,【一直到年還是恐怖的,一般不會的-_-||】

擴展【糾正】一下以前寫的,以前寫的是沒錯,但是針對於self.這樣來寫屬性的話,屬性名和方法名相同的話,屬性會覆蓋方法,而以前寫得的是誰在下面誰優先級高恢復高以前的,這個寫的也沒錯,但是誰在下面誰覆蓋上面針對的屬性是不帶self的

就是!:如果一個類中含有self.name1=屬性  與def name1():   無論誰在前在后,self.name1屬性是會覆蓋name1的方法的

而如果是name 與 def name1():  誰在前誰被覆蓋!這個應該沒問題

針對的主要是self內!!!

報的異常:

在此提醒:類中的屬性不能被變更為方法!!!切記切記!!這個屬性指的是self下的屬性!!也需要切記切記!!!

 

小甲魚這個寫法可比我簡單啊 這個思路雖然跟我很像,但是我感覺這樣寫好巧啊,省了好多的代碼啊 好清晰!!

下面這個和我上面一樣沒考慮時間為負值哦

 

 方法前加一個下划線變成偽私有,屬性前加倆個下划線變成偽私有

 

下方這個是我搞出的最終版

 

import time as t

class Mytimer:#self所有指的都是我實例化出來的!(那個對象)!,無論在哪個方法內的self都一樣
    #相加
    def __add__(self,other):
        self.prompt="二者總共持續了"
        result=[]
        for i in range(0,6):
            result.append(self.arr[i]+other.arr[i])
            if result[i]:#如果不是0
                self.prompt+=str(result[i])+str(self.unit[i])
        return self.prompt
    #事先定義防止出錯
    def __init__(self):
        self.prompt="未調用stop()方法"
        self.begin=0
        self.end=0
        self.unit=['','','','小時','分鍾','']
        self.arr=[0,0,0,0,0,0]#這個是為了解決__add__方法如果運行方法,防止報錯,沒運行讓他為就好
    #print出來顯示
    def __str__(self):
        return self.prompt

    #實例化對象返回出來
    __repr__=__str__
    
    #計時開始
    def start(self):
        print("計時開始...")
        self.begin=t.localtime() #這里不能寫start否則類的屬性會使得start方法失效

    #計時結束
    def stop(self):
        #print(self)
        if not self.begin:#沒有!self.begin這樣寫的哦
            print("請先調用start()方法")
        else:
            self.end=t.localtime()
            self._lasttime()
            print("計時結束")

    #持續時間
    def _lasttime(self):#方法前面加上一個下划線,編程偽私有
        #時間返回的是一個元組形式,索引前六個分別是年月日時分秒
        self.arr=[]#按照年月日時分秒差值6單位個添加進去【持續時間】
        self.prompt="總共持續了:"
        for i in range(6):
            self.arr.append(self.end[i]-self.begin[i])
            #if self.arr[i]:#如果不是0
                #self.prompt+=str(self.arr[i])+str(self.unit[i])

        #解決出現減出負號的問題
        arrlist=[5,4,3,2,1,0]
        arrlist1=['這個肯定不用',12,30,12,60,60]#30那個有的月份是31 2月也可能反正很多
        for i in arrlist:
            if self.arr[i]<0:
                self.arr[i]+=arrlist1[i]
                self.arr[i-1]-=1
        for i in range(0,6):
            if self.arr[i]:#如果不是0
                self.prompt+=str(self.arr[i])+str(self.unit[i])
        print(self.prompt)
        #執行完歸零方便下次調用
        self.begin=0
        self.end=0
        

 

·~~~屬性訪問~~~

 下放圖,setattr這 寫return也是一樣的

無論屬性存不存在,獲取屬性第一個走的方法就是__getattribute__(),他必須有renturn,否則當該屬性不存在的時候也不會執行__getattr__()方法

 

 下圖這樣寫會進入死循環

 

解決方案:

   或者這樣寫也可以:  .__dict__是把所有屬性以字典的形式返回出來

     ~~~描述符(property的原理)~~~

 ·就是當我把這個特殊的類實例化賦給了另一個類的屬性的時候,之后實例化那個類,操作那個屬性的時候就操作我這個特殊類的__get__等方法

self:指的是我這個特殊的類的實例,就是另一個類中賦予的那個屬性

instance:指的是另一個類的實例化

owner:指的是指的是另一個類

                   

 

下圖中不是__del__而是__delete__  【__del__是被垃圾回收機制回收該塊實例化占的內存的時候調用】

 

 

 

下圖中的self指的是該類的實例化fah,而不是那個類

 

 

  協議

對於列表、元組、字典等等都是容器,那么接下來談一談容器的協議

 

 

 

 

 

 

 

#用數組表示          #牢記可變參數*啊
class List:
    def __init__(self,*arg):
        self.count=[0 for x in arg]#把前面0換成x這就是把arg每個參數都賦值給列表
        self.values=[]
        for i in arg:
            self.values.append(i)
    def __len__(self):
        return len(self.values)
    def __getitem__(self,key):
        self.count[key]+=1
        return self.values[key]
    def __delitem__(self,key):
        del self.count[key]
        del self.values[key]

#用字典表示數量
class CountList:
    def __init__(self,*args):
        self.values=[x for x in args]
        #他使用的是字典
        self.count={}.fromkeys(range(len(self.values)),0) #這種形式{0: 0, 1: 0, 2: 0, 3: 0, 4: 0}

    def __len__(self):
        return len(self.values)
    def __getitem__(self,key):
        self.count[key]+=1
        return self.values[key]
    def __delitem__(self,key):
        del self.count[key]
        del self.values[key]
        self.countTemp={}.fromkeys(range(len(self.values)),0)
        for i in range(len(self.values)):
            if i<key:
                self.countTemp[i]=self.count[i]
            else:
                self.countTemp[i]=self.count[i+1]
        self.count=self.countTemp

 

迭代器~~!!

  迭代:序列(列表 元組 字符串 字典)

iter()生成迭代序列

next()開始尋找下一個元素

如果迭代全部完成next再次執行會拋出StopIteration的異常

我們可以通過while寫出for循環的原理

 

那么關於迭代器的魔法方法有倆個,就是對應的前倆個BIF的實現

 

 本身就是迭代,因此在__iter__寫的就是self  

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM