Python基礎筆記-11

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

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

魔法方法的‘魔力’體現再他們總能再適當的時候被自動調用

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

有時候在類定義是寫__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[,...]) 實際上在實例化的時候先自動調用了這個魔法方法,之后才自動調用了__init__魔法方法

該魔法方法的參數是這個類

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

這個new方法一般很少去重寫,一般讓python用默認的方法去執行就行

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

>>> class CapStr(str):

???def __new__(cls,string):

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

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

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

>>> a

'HAHAH'

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

>>> class C:

???def __init__(self):

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

???def __del__(self):

??????print('我是__del__方法,我被調用了')

>>> c=C()

我是__init__方法,我被調用了

>>> c1=c

>>> c2=c1

>>> c3=c2

>>> c4=c3

>>> del c1

>>> del c

>>> del c2

>>> del c3

>>> del c4

我是__del__方法,我被調用了

4)算數魔法方法當你的對象進行了算數操作的時候,以下魔法方法就會自動被調用,這些方法可以被重寫

__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):定義整數除法行為://

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

__divmod__(self,other):定義當被divmod()調用時的行為

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

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

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

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

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

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

【反運算魔法方法(上面的所有魔法方法前面加上r)】當a+b,a是一個數值,那么不能利用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方法代表啟動計時和停止計時

假設計時器對象t1,print(t1)和直接調用t1均顯示結果

當計時器未啟動或已經停止計時,調用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

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

__str__

>>> class A:

???def __str__(self):

??????return 'hahah'

>>> a=A()

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

hahah

__repr__

>>> class B:

???def __repr__(self):

??????return 'haha'

>>> b=B()

>>> b #__repr__就是當要對實例化對象直接敲回車的時候要自動調用的魔法方法

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('計時結束')

???#內部方法,計算運行時間

???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()

計時結束

>>> t1

總過運行了15秒

>>> t2=MyTimer()

>>> t2.start()

計時開始。。

>>> t2.stop()

計時結束

>>> t2

總過運行了5秒

>>> t1+t2

'總共運行了20秒'

>>>

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

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

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

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

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

>>> 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

#以下例子會造成改造魔法方法后的死循環

class Rectangle:

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

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

???????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)描述符:將某種特殊類型的類的實例指派給另一個類的屬性

特殊類型是實現以下三個方法一個或者多個的類就是特殊類型的類

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

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

__delete__(self,instance)控制刪除操作,不返回任何內容

>>> 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? #調用MyDecriptor的__get__方法

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

>>> test

<__main__.Test object at 0x0000012E3FF4D898>

>>> Test

>>> test.x='x-man' #調用MyDecriptor的__set__方法

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

>>> del test.x? #調用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'

#以下是一個溫度計數值轉化的練習

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

要求兩個屬性會自動進行轉換,也就是說你可以給攝氏度這個屬性賦值,然后打印的華氏度屬性是自動轉換后的結果

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()

調用后

>>>

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

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

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

26.0

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

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

86.0

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

>>> temp.cel

37.77777777777778

>>>

8)定制序列

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

容器類型的協議

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

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

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

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) #調用__init__方法

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

>>> c1[1] #調用__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()? 對一個容器對象調用該bif可以得到一個迭代器

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

當迭代器沒有值返回系統會返回報錯

>>> 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實現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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Python 面向對象Python從設計之初就已經是一門面向對象的語言,正因為如此,在Python中創建一個類和對...
    順毛閱讀 4,236評論 4 16
  • 八大排序 - Shuai-Xie - Github 內部排序和外部排序 內部排序數據少,數據記錄在內存中進行排序,...
    謝小帥閱讀 1,111評論 1 1
  • 散步在午后的校園 三月,天轉暖 一切都欣欣然 雨后小徑的泥土,踩起來 一定是涼爽又溫柔。...
    兩條路閱讀 193評論 0 0
  • 最近根據公司的業務需要,封裝了一些平時開發中基本都會用到的基礎業務模塊,其中用的最多的就是各個工廠模式了,同時也趁...
    Knight_Davion閱讀 8,075評論 7 27