1、基礎知識
定義:當類中提供了某個特殊名稱的方法,在該類的實例出如今它們相關的表達式時,Python自動調用它們
特性:
一、運算符重載讓類攔截常規的Python運算。
二、類可重載全部Python表達式運算符。
三、類可重載打印,函數調用,屬性點號運算等內置運算
四、重載使類實例的行爲像內置類型
五、重載是經過提供特殊名稱的類方法來實現的
2、字典索引和分片:__getitem__,__setitem__,__delitem__
若是在類中定義了(或者繼承了)的話,則對於實例中的索引運算,會自動調用__getitem__,__setitem__,__delitem__三個方法。當實例X出現X[i]這樣的索引運算時,Python會調用這個實例繼承的__getitem__,__setitem__,__delitem__方法(若是有的話)
class Foo:
def __init__(self,name):
self.name=name
def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key]=value
def __delitem__(self, key):
del self.__dict__[key]
F=Foo('egon') #實例化
print(F['name']) #打印,以字典索引的方式,會找到__getitem__方法下的代碼,‘name’傳遞給第二個參數
F['age']=18 #賦值操做,直接傳遞給__setitem__方法
print(F.__dict__) #打印F的命名空間
del F['age'] #del會調用__delitem__方法,刪除‘age’
print(F.__dict__)
打印結果爲:
egon
{'name': 'egon', 'age': 18}
{'name': 'egon'}
3、__slots__
__slots__:實例化的對象將沒有名稱空間,都保存在類的名稱空間,並且只能設置指定的屬性,例以下面的例子,每一個實例只能設置x,y,z三個屬性
class People:
__slots__=['x','y','z']
p=People
p.x=1
p.y=2
p.z=3
print(People.__dict__)
p.e=4 #這個將會報錯
4、迭代器對象:__iter__,__next__
python 中全部的迭代環境都會先嚐試__iter__方法,再嘗試__getitem__,也就是說,只有對象在不支持迭代的狀況下,纔會嘗試索引的方式運算。
Python中,迭代環境是經過調用內置函數iter去嘗試尋找__iter__方法來實現的,而這種方法返回一個迭代器對象,若是已經提供了,Python就會重複調用這個迭代器對象的next方法,知道發生了StopIteration異常
class Range:
def __init__(self,start,end,long): #構造函數,定義三個元素,start,end,long
self.start=start
self.end=end
self.long=long
def __iter__(self): #__iter__:生成迭代器對象self
return self #返回這個迭代器自己
def __next__(self): #__next__:一個一個返回迭代器內的值
if self.start>=self.end:
raise StopIteration
n=self.start
self.start+=self.long
return n
r=Range(1,10,2) #實例化對象r,
for i in r: #r會首先調用__iter__方法,把本身轉換爲迭代器
print(i)
5、實現上下文管理:with/as,__enter__,__exit__
with open('a.txt') as f:#with代碼塊後會自定關閉文件,不管是否發生異常,一下是with的工做方式:
一、計算表達式,所獲得的對象稱爲環境管理器,他必須有__enter__,__exit__方法。
二、環境管理器的__enter__方法會被調用。若是as字句存在,器返回值會賦值給as字句中的變量,不然直接丟棄。
三、代碼塊中嵌套的代碼會執行。
四、若是with代碼塊引起異常,__exit__(type,value,traceback)方法就會調用(帶有異常細節)
五、若是with代碼塊沒有引起異常,__exit__方法依然會被調用,其type,value,traceback參數都會以none傳遞
import time
class Open:
def __init__(self,filepath,mode='r',encoding='utf8'):
self.filepath=filepath
self.mode=mode
self.encoding=encoding
self.x=open(filepath,mode=mode,encoding=encoding)
def write(self,line):
t=time.strftime('%Y-%m-%d %X')
self.x.write('%s %s' %(t,line))
def __getattr__(self, item):
return getattr(self.x,item)
def __enter__(self):
print("*************")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('文件關閉')
self.x.close()
with Open('a.txt','w') as f: #出現with語句,對象的__enter__被觸發,有返回值則賦值給as聲明的變量
f.write("abc") #調用本身定義的write方法,把‘abc’ 寫入到a.txt文件
print('==============') #這一行代碼執行完畢後,會觸發__exit__方法,關閉文件
print("繼續執行代碼")
#代碼執行以下
*************
==============
文件關閉
繼續執行代碼
6、__call__:python會爲實例用函數調用的表達式運行__call__方法,這樣就可讓類實例的外觀看起來像是函數
class callee:
def __call__(self, *args, **kwargs):
print('call:',args,kwargs)
C=callee()
C(1,2,3) #實例加()後,會調用__call__方法
C(1,2,3,X=4,Y=5)
#打印結果以下
call: (1, 2, 3) {}
call: (1, 2, 3) {'X': 4, 'Y': 5}
7、__del__:析構函數
每當實例產生時,就對調用__init__構造函數,沒當實例空間被收回時,就會調用__del__析構函數。吃方法通常不需定義,python 有本身的內存回收機制
import time
class Open:
def __init__(self,filepath,mode='r',encoding='utf8'):
self.filepath=filepath
self.mode=mode
self.encoding=encoding
self.x=open(filepath,mode=mode,encoding=encoding)
def __del__(self):
print('del')
self.x.close()
f=Open('a.txt','w')
del f