Python基礎(chǔ)筆記-11

70.魔法方法:http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&highlight=%C4%A7%B7%A8%B7%BD%B7%A8

魔法方法總是被雙下劃線包圍距帅,例如__init__

魔法方法的‘魔力’體現(xiàn)再他們總能再適當(dāng)?shù)臅r候被自動調(diào)用

1)__init__(self[,...])類在實例化對象的時候篡殷,首先會調(diào)用的一個方法

有時候在類定義是寫__init__方法猜年,有時候卻沒有奥溺,這是為什么呢?

>>> class Rectangle:

???def __init__(self,x,y):

??????self.x=x

??????self.y=y

???def getPeri(self):

??????return (self.x+self.y)*2

???def getArea(self):

??????return self.x*self.y

>>> rect=Rectangle(3,4)

>>> rect.getPeri()

14

>>> rect.getArea()

12

#__init__不能有返回值

>>> class A:

???def __init__(self):

??????return 'haha'

>>> a=A()

Traceback (most recent call last):

?File "", line 1, in

???a=A()

TypeError: __init__() should return None, not 'str'

2)__new__(cls[,...]) 實際上在實例化的時候先自動調(diào)用了這個魔法方法迎膜,之后才自動調(diào)用了__init__魔法方法

該魔法方法的參數(shù)是這個類

這個方法的返回值是一個實例對象牡借,通常返回cls這個類的實例對象混弥,也可以返回其他類的對象

這個new方法一般很少去重寫,一般讓python用默認(rèn)的方法去執(zhí)行就行

當(dāng)繼承一個不可變類型但需要進(jìn)行修改需要重寫這個方法

>>> class CapStr(str):

???def __new__(cls,string):

??????string=string.upper()

??????return str.__new__(cls,string)

>>> a=CapStr('hahah') #由于CapStr這個類是繼承了str類荐吉,str是不可改變的類焙糟,那么就不能修改str的__init__方法進(jìn)行修改,所以應(yīng)該在重寫__new__样屠,增加了將字符串轉(zhuǎn)化成大寫然后再調(diào)用父類str的__new__的方法

>>> a

'HAHAH'

3)__del__(self)析構(gòu)方法穿撮,當(dāng)對象被銷毀時候自動調(diào)用(當(dāng)垃圾回收機(jī)制自動銷毀的時候:實例化對象都沒有引用了的時候)

>>> class C:

???def __init__(self):

??????print('我是__init__方法,我被調(diào)用了')

???def __del__(self):

??????print('我是__del__方法痪欲,我被調(diào)用了')

>>> c=C()

我是__init__方法悦穿,我被調(diào)用了

>>> c1=c

>>> c2=c1

>>> c3=c2

>>> c4=c3

>>> del c1

>>> del c

>>> del c2

>>> del c3

>>> del c4

我是__del__方法叙赚,我被調(diào)用了

4)算數(shù)魔法方法當(dāng)你的對象進(jìn)行了算數(shù)操作的時候歹嘹,以下魔法方法就會自動被調(diào)用,這些方法可以被重寫

__add__(self呀伙,other):定義加法行為+

__sub__(self,other):定義減法行為-

>>> class New_int(int):

???def __add__(self,other):

??????return int.__sub__(self,other)

???def __sub__(self,other):

??????return int.__add__(self,other)

>>> a=New_int(3)

>>> b=New_int(5)

>>> a+b

-2

__mul__(self,other):定義乘法行為*

__truediv__(self,other):定義真除法行為/

__floordiv__(self,other):定義整數(shù)除法行為://

__mod__(self,other):定義取模算法的行為:%

__divmod__(self,other):定義當(dāng)被divmod()調(diào)用時的行為

__pow__(self,other):定義當(dāng)被power()調(diào)用或**運算時的行為

__lshift__(self,other):定義按位左移位的行為:<<

__rshift__(self,other):定義按右移位的行為>>

__and__(self,other):定義按位與操作的行為&

__xor__(self,other):定義按位異或操作的行為^

__or__(self,other):定義按位或操作的行為|

【反運算魔法方法(上面的所有魔法方法前面加上r)】當(dāng)a+b蛙埂,a是一個數(shù)值欲账,那么不能利用a的魔法方法罢洲,只用利用b的r魔法方法殿较,反魔法方法也可以改寫

>>> class Nint(int):

???def __radd__(self,other):

??????return int.__sub__(self,other)

>>> a=Nint(5)

>>> b=Nint(3)

>>> a+b

2

>>> 1+b

2

【增量運算符】a+=1 上面所有的魔法方法前面家i

【一元操作符】-a

5)案例練習(xí)

定制一個計時器的類

start和stop方法代表啟動計時和停止計時

假設(shè)計時器對象t1洽瞬,print(t1)和直接調(diào)用t1均顯示結(jié)果

當(dāng)計時器未啟動或已經(jīng)停止計時为障,調(diào)用stop方法會給予溫馨提示

兩個計時器對象可以進(jìn)行相加:t1+t2

只能使用提供的有限資源完成

資源如下:

使用time模塊的localtime方法獲取當(dāng)前時間

time.localtime返回struct_time的時間格式(time模塊詳解http://bbs.fishc.com/forum.php?mod=viewthread&tid=51326&highlight=time%2B%C4%A3%BF%E9%CF%EA%BD%E2

表現(xiàn)你的類:__str__和__repr__:由于要求輸入t1回車顯示結(jié)果(__repr__)和print(t1)(__str__)顯示結(jié)果果則需要重寫這倆魔法函數(shù)

__str__

>>> class A:

???def __str__(self):

??????return 'hahah'

>>> a=A()

>>> print(a) #__str__就是當(dāng)要print出來一個實例化對象的時候要自動調(diào)用的魔法方法

hahah

__repr__

>>> class B:

???def __repr__(self):

??????return 'haha'

>>> b=B()

>>> b #__repr__就是當(dāng)要對實例化對象直接敲回車的時候要自動調(diào)用的魔法方法

haha

[1]編寫代碼模塊MyTime.py

import time as t

class MyTimer():

???def __init__(self):

???????self.unit=['年','月','日','時','分','秒']

???????self.prompt= '未開始計時'

???????self.begin=0

???????self.end=0

???????self.lasted=[]

???def __str__(self):

???????return self.prompt

???__repr__=__str__

???def __add__(self,other):

???????prompt='總共運行了' #局部變量

???????result=[]

???????for index in range(6):

???????????result.append(self.lasted[index]+other.lasted[index])

???????????if result[index]:

???????????????prompt+=(str(result[index])+self.unit[index])

???????return prompt

???#開始計時

???def start(self):

???????self.begin=t.localtime()

???????self.prompt='請先stop'

???????print('計時開始。。')

???#停止計時

???def stop(self):

???????if not self.begin:

???????????print('請先start')

???????else:

???????????self.end=t.localtime()

???????????self._calc()

???????????print('計時結(jié)束')

???#內(nèi)部方法伴逸,計算運行時間

???def _calc(self):

???????self.lasted=[]

???????self.prompt= '總過運行了'

???????for index in range(6):

???????????self.lasted.append(self.end[index]-self.begin[index])

???????????if self.lasted[index]:

???????????????self.prompt+=(str(self.lasted[index])+self.unit[index])

???????#為下一輪初始化變量

???????self.begin=0

???????self.end=0

[2]運行代碼模塊

>>>

===================== RESTART: D:/python/3.5.1/Mytime.py =====================

>>> t1=MyTimer()

>>> t1

未開始計時

>>> t1.stop()

請先start

>>> t1.start()

計時開始顷锰。州藕。

>>> t1.start()

計時開始笨枯。。

>>> t1

請先stop

>>> t1.stop()

計時結(jié)束

>>> t1

總過運行了15秒

>>> t2=MyTimer()

>>> t2.start()

計時開始遇西。馅精。

>>> t2.stop()

計時結(jié)束

>>> t2

總過運行了5秒

>>> t1+t2

'總共運行了20秒'

>>>

6)魔法方法對于屬性訪問的用用

__getattr__(self,name):定義當(dāng)用戶試圖獲取一個不存在的屬性時候會被自動調(diào)用的方法

__getattribute__(self,name):定義當(dāng)該類的屬性被訪問的時候會自動調(diào)用的方法

__setatter__(self,name,value):定義當(dāng)一個屬性被設(shè)置時候,會自動調(diào)用的方法

__delattr__(self,name):定義當(dāng)一個屬性被刪除時候會自動調(diào)用的方法

>>> class C:

???def __getattribute__(self,name):

??????print('getattribute')

??????return super().__getattribute(name)

???def __getattr__(self,name):

??????print('getattr')

???def __setattr__(self,name,value):

??????print('setattr')

??????super().__setattr__(name,value)

???def __delattr__(self,name):

??????print('delattr')

??????super().__delattr__(name)

>>> c=C()

>>> c.x

getattribute

getattr

>>> c.x=1

setattr

>>> c.x

getattribute

getattr

>>> del c.x

delattr

#以下例子會造成改造魔法方法后的死循環(huán)

class Rectangle:

???def __init__(self,width=0,height=0):

???????self.width=width #既然發(fā)生賦值操作就會自動除法__setattr__但是這個魔法方法被改造后里頭又有一個賦值粱檀,所以會死循環(huán)

???????self.height=height

???def __setattr__(self,name,value):

???????if name=='square':

???????????self.width=value

???????????self.height=value

???????else:

???????????self.name=value

???def getAre(self):

???????return self.width*self.height

7)描述符:將某種特殊類型的類的實例指派給另一個類的屬性

特殊類型是實現(xiàn)以下三個方法一個或者多個的類就是特殊類型的類

__get__(self,instance,owner)用于訪問屬性洲敢,它返回屬性的值

__set__(self,instance,value)將再屬性分配操作中調(diào)用,不返回任何內(nèi)容

__delete__(self,instance)控制刪除操作茄蚯,不返回任何內(nèi)容

>>> class MyDecriptor: #這個類含有上述三個方法

???def __get__(self,instance,owner):

??????print('getting...',self,instance,owner)

???def __set__(self,instance,value):

??????print('setting...',self,instance,value)

???def __delete__(self,instance):

??????print('deleting...',self,instance)

>>> class Test:

???x=MyDecriptor() #把MyDecriptor這個類的實例MyDecriptor() 賦值給 Test類的屬性x压彭,那么這個MyDecriptor類就是描述符類

>>> test=Test()

>>> test.x? #調(diào)用MyDecriptor的__get__方法

getting... <__main__.MyDecriptor object at 0x0000012E3FF4D748> <__main__.Test object at 0x0000012E3FF4D898>

>>> test

<__main__.Test object at 0x0000012E3FF4D898>

>>> Test

>>> test.x='x-man' #調(diào)用MyDecriptor的__set__方法

setting... <__main__.MyDecriptor object at 0x0000012E3FF4D748> <__main__.Test object at 0x0000012E3FF4D898> x-man

>>> del test.x? #調(diào)用MyDecriptor的__del__方法

deleting... <__main__.MyDecriptor object at 0x0000012E3FF4D748> <__main__.Test object at 0x0000012E3FF4D898>

以下是編寫自己的property類

>>> class Myproperty:

???def __init__(self,fget=None,fset=None,fdel=None):

??????self.fget=fget

??????self.fset=fset

??????self.fdel=fdel

???def __get__(self,instance,owner):

??????return self.fget(instance)

???def __set__(self,instance,value):

??????self.fset(instance,value)

???def __del__(self,instance):

??????self.fdel(instance)

>>> class C:

???def __init__(self):

??????self._x=None

???def getx(self):

??????return self._x

???def setx(self,value):

??????self._x=value

???def delx(self):

??????del self._x

???x=Myproperty(getx,setx,delx)

>>> c=C()

>>> c.x='haha'

>>> c.x

'haha'

>>> x._x

Traceback (most recent call last):

?File "", line 1, in

???x._x

NameError: name 'x' is not defined

>>> c,_x

Traceback (most recent call last):

?File "", line 1, in

???c,_x

NameError: name '_x' is not defined

>>> c._x

'haha'

#以下是一個溫度計數(shù)值轉(zhuǎn)化的練習(xí)

先定義一個溫度類,然后定義兩個描述符類喲關(guān)于描述攝氏度和華氏度兩個屬性

要求兩個屬性會自動進(jìn)行轉(zhuǎn)換渗常,也就是說你可以給攝氏度這個屬性賦值壮不,然后打印的華氏度屬性是自動轉(zhuǎn)換后的結(jié)果

class Celsius:

???def __init__(self,value=26.0):

???????self.value=float(value)

???def __get__(self,instance,owner):

???????return self.value

???def __set__(self,instance,value):

???????self.value=float(value)

class Fahrenheit:

???def __get__(self,instance,owner):

???????return instance.cel*1.8+32

???def __set__(self,instance,value):

???????instance.cel=(float(value)-32)/1.8

class Temperature:

???cel=Celsius()

???fah=Fahrenheit()

調(diào)用后

>>>

====================== RESTART: D:/python/3.5.1/temp.py ======================

>>> temp=Temperature()#實例化對象此時調(diào)用了__init__方法,使得temp的value=26.0

>>> temp.cel? #這個操作會觸發(fā)Celsius描述符的__get__方法皱碘,返回對象temp的value

26.0

>>> temp.cel=30 #這個操作會觸發(fā)Celsius描述符的__set__方法询一,將對象的value修改成30

>>> temp.fah #這個操作會觸發(fā)Fahrenheit描述符的__get__方法

86.0

>>> temp.fah=100 #這個操作會觸發(fā)Fahrenheit描述符的__set__方法

>>> temp.cel

37.77777777777778

>>>

8)定制序列

協(xié)議與其他編程語言中的接口很相似,他對丁你哪些方法必須要定義

容器類型的協(xié)議

如果說希望定制的容器是不可變的話癌椿,你只需要定義__len__()和__getitem__()方法

如果說你希望定制的容器是可變的話健蕊,除了__len__()和__getitem__()方法,你還需要定義__setitem__()和__delitem__()兩個方法

編寫一個不可改變的自定義列表踢俄,要求記錄列表中每個元素被訪問的次數(shù)

class Countlist:

???def __init__(self,*args):

???????self.values=[x for x in args]

???????self.count={}.fromkeys(range(len(self.values)),0)

???def __len__(self):

???????return len(self.values)

???def __getitem__(self,key):

???????self.count[key]+=1

???????return self.values[key]

運行腳本

>>>

=================== RESTART: D:/python/3.5.1/Countlist.py ===================

>>> c1=Countlist(1,3,5,7,9) #調(diào)用__init__方法

>>> c2=Countlist(2,4,6,8,10)

>>> c1[1] #調(diào)用__getitem__方法

3

>>> c2[1]

4

>>> c1[1]+c2[1]

7

>>> c1.count

{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}

9)迭代器 http://bbs.fishc.com/forum.php?mod=viewthread&tid=56023&highlight=yield

iter()? 對一個容器對象調(diào)用該bif可以得到一個迭代器

next() 對一個迭代器調(diào)用該big可以返回一個值

當(dāng)?shù)鳑]有值返回系統(tǒng)會返回報錯

>>> string='fishc'

>>> it=iter(string)

>>> next(it)

'f'

>>> next(it)

'i'

>>> next(it)

's'

>>> next(it)

'h'

>>> next(it)

'c'

>>> next(it)

Traceback (most recent call last):

?File "", line 1, in

???next(it)

StopIteration

用這里的兩個bif實現(xiàn)for的作用

>>> string='fishc'

>>> it=iter(string)

>>> while True:

???try:

??????each=next(it)

???except StopIteration:

??????break

???print(each)

f

i

s

h

c

#利用__iter__() 和 __next__()方法

>>> class Fibs:

???def __init__(self,n=10):

??????self.a=0

??????self.b=1

??????self.n=n

???def __iter__(self):

??????return self

???def __next__(self):

??????self.a,self.b=self.b,self.a+self.b

??????if self.a>self.n:

?????????raise StopIteration

??????return self.a

>>> fibs=Fibs()

>>> for each in fibs:

???print(each)

1

1

2

3

5

8

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缩功,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子都办,更是在濱河造成了極大的恐慌嫡锌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脆丁,死亡現(xiàn)場離奇詭異世舰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)槽卫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胰蝠,“玉大人歼培,你說我怎么就攤上這事震蒋。” “怎么了躲庄?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵查剖,是天一觀的道長。 經(jīng)常有香客問我噪窘,道長笋庄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任倔监,我火速辦了婚禮直砂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浩习。我一直安慰自己静暂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布谱秽。 她就那樣靜靜地躺著洽蛀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疟赊。 梳的紋絲不亂的頭發(fā)上郊供,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機(jī)與錄音近哟,去河邊找鬼驮审。 笑死,一個胖子當(dāng)著我的面吹牛椅挣,可吹牛的內(nèi)容都是我干的头岔。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼鼠证,長吁一口氣:“原來是場噩夢啊……” “哼峡竣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起量九,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤适掰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后荠列,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體类浪,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年肌似,在試婚紗的時候發(fā)現(xiàn)自己被綠了费就。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡川队,死狀恐怖力细,靈堂內(nèi)的尸體忽然破棺而出睬澡,到底是詐尸還是另有隱情,我是刑警寧澤眠蚂,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布煞聪,位于F島的核電站,受9級特大地震影響逝慧,放射性物質(zhì)發(fā)生泄漏昔脯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一笛臣、第九天 我趴在偏房一處隱蔽的房頂上張望云稚。 院中可真熱鬧,春花似錦捐祠、人聲如沸碱鳞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窿给。三九已至,卻和暖如春率拒,著一層夾襖步出監(jiān)牢的瞬間崩泡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工猬膨, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留角撞,地道東北人。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓勃痴,卻偏偏與公主長得像谒所,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子沛申,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容