此前我們已經解除了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