python運算符重載(二)

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
相關文章
相關標籤/搜索