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)再他們總能再適當?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用默認的方法去執(zhí)行就行

當繼承一個不可變類型但需要進行修改需要重寫這個方法

>>> class CapStr(str):

???def __new__(cls,string):

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

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

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

>>> a

'HAHAH'

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

>>> 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ù)魔法方法當你的對象進行了算數(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):定義當被divmod()調(diào)用時的行為

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

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

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

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

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

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

【反運算魔法方法(上面的所有魔法方法前面加上r)】當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)案例練習

定制一個計時器的類

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

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

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

兩個計時器對象可以進行相加:t1+t2

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

資源如下:

使用time模塊的localtime方法獲取當前時間

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__就是當要print出來一個實例化對象的時候要自動調(diào)用的魔法方法

hahah

__repr__

>>> class B:

???def __repr__(self):

??????return 'haha'

>>> b=B()

>>> b #__repr__就是當要對實例化對象直接敲回車的時候要自動調(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):定義當用戶試圖獲取一個不存在的屬性時候會被自動調(diào)用的方法

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

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

__delattr__(self,name):定義當一個屬性被刪除時候會自動調(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)化的練習

先定義一個溫度類,然后定義兩個描述符類喲關(guā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可以返回一個值

當?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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容