12.詳解python常用到的魔術(shù)方法

python中,用“__”雙下劃線包起來的方法,統(tǒng)稱“魔術(shù)方法”;

比如最常用的init,此方法定義一個對象的初始操作,然而在調(diào)用p = someclass()的時候,在init前面還調(diào)用了一個new方法,兩個共同構(gòu)成了“構(gòu)造函數(shù)”;

1、 initnew方法

new用來創(chuàng)建類并返回這個類的實例;init只是將傳入的參數(shù)來初始化該實例。

class Demo:
    def __init__(self):
        print("如果不在__new__方法里面調(diào)object的__new__方法就不會創(chuàng)建對象,__init__不會被執(zhí)行")
        print("如果不在__new__方法里面調(diào)return創(chuàng)建好的對象,__init__不會被執(zhí)行")
    def __new__(cls, *args, **kwargs):
        print("__new__方法通過調(diào)用object類的__new__方法創(chuàng)建對象,再把對象傳遞給__init__方法")
        return super().__new__(cls,*args,**kwargs)

if __name__ == '__main__':
    cl = Demo()

# 輸出:
__new__方法通過調(diào)用object類的__new__方法創(chuàng)建對象,再把對象傳遞給__init__方法
如果不在__new__方法里面調(diào)object的__new__方法就不會創(chuàng)建對象,__init__不會被執(zhí)行
如果不在__new__方法里面調(diào)return創(chuàng)建好的對象,__init__不會被執(zhí)行

總結(jié):
1、觸發(fā)方式,實例化類的時候自動調(diào)用;
2、作用,創(chuàng)建類實例;
3、new()方法執(zhí)行順序在init()之前
4、如果不在new方法里面調(diào)object的new方法就不會創(chuàng)建對象,init不會被執(zhí)行;
5、如果不在new方法里面調(diào)return創(chuàng)建好的對象,init不會被執(zhí)行。

2、del方法

在對象生命周期調(diào)用結(jié)束時,del方法會被調(diào)用,可以理解為“構(gòu)析函數(shù)”。一般可以省略

# 實際應(yīng)用
from os.path import join

class Demo:
    def __init__(self,filepath='',filename='a.txt'):
        ''' 給文件進行包裝,從而確認文件在刪除時,進行關(guān)閉 '''
        self.file = open(join(filepath,filename),'r+')
    def __del__(self):
        self.file.close()
        del self.file

if __name__  == '__main__':
    cl = Demo()

3、call方法

定義了該方法的對象稱為可調(diào)用對象,即該對象可以像函數(shù)一樣被調(diào)用


# __call__方法,可調(diào)用對象callable,自定義函數(shù)、內(nèi)置函數(shù)、類都屬于可調(diào)用對象,即可以把()應(yīng)用在某對象身上稱為可調(diào)用對象

class Demo:
    def __init__(self):
        print("111")
    def __call__(self):
        print("222")
if __name__ == '__main__':
    cl = Demo()
    cl()
    print(callable(cl))   # 判斷函數(shù)是否為可調(diào)用函數(shù)用函數(shù)callable

# 輸出:
111
222
True

總結(jié):
1、觸發(fā)方式,將類實例像調(diào)函數(shù)一樣調(diào)用的時候自動調(diào)用;
2、作用讓類實例可以像調(diào)函數(shù)一樣調(diào)用;
3、構(gòu)造方法new的執(zhí)行是由創(chuàng)建對象觸發(fā),即:對象 = 類名();
4、對于call方法的執(zhí)行是由對象后加括號觸發(fā)的,即對象()或類()

實際應(yīng)用
class GDistance:
    def __init__(self,g):
        self.g = g
    def __call__(self,t):
        return (self.g*t**2)/2

# 調(diào)用可調(diào)用對象
e_g = GDistance(9.8)
for t in range(3):
    print("%d秒 下降 %.2f"%(t, e_g(t)))

# 輸出:
0秒 下降 0.00
1秒 下降 4.90
2秒 下降 19.60

4、自定義容器的magic method

通過字典形式操作屬性值(獲取,設(shè)置,刪除)觸發(fā)以上三個方法。
區(qū)別:"."點的形式操作跟attr相關(guān),"[]"中括號形式操作跟item相關(guān)

首先,實現(xiàn)不可變?nèi)萜鞯脑?,你只能定義 lengetitem 。
可變?nèi)萜鲄f(xié)議則需要所有不可變?nèi)萜鞯乃校硗膺€需要 setitemdelitem 。

class Demo:
    def __init__(self,name):
        self.name = name

    def __setitem__(self, key, value):
        print("執(zhí)行obj[key]=value的時候觸發(fā)__setitem__方法")
        self.__dict__[key] = value  # 給類中的屬性值分配值,定制特有屬性

    def __getitem__(self, item):
        print("執(zhí)行obj[key]獲取實例屬性的時候觸發(fā)__getitem__方法")
        return self.__dict__[item]

    def __delitem__(self, key):
        print("調(diào)用delitem")
        self.__dict__.pop(key)

if __name__ == '__main__':
    c1 = Demo({"name":"tly","age":20})
    c1['age'] = 18       # 執(zhí)行setitem
    print(c1['name'])    # 執(zhí)行g(shù)etitem
    del c1['age']        # 執(zhí)行delitem

5、 iter

如果你希望你的對象是可迭代的話,你需要定義 iter 會返回一個迭代器。迭代器必須遵循迭代器協(xié)議,需要有 iter(返回它本身) 和 next

5、迭代器 中講到這點,可點擊查看

最后編輯于
?著作權(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)容