您現在的位置是:首頁 > 綜藝首頁綜藝

Python的魔法方法:原來是你

由 思路實驗室 發表于 綜藝2022-11-29
簡介既然如此,我們就可以使用__init__方法在不修改物件記憶體地址的情況下對其進行重新初始化:需要注意的是當我們複製一個例項時,也會依次呼叫__new__方法和__init__方法

shell怎麼拼讀

Python的魔法方法:原來是你

大家好,歡迎收看思路實驗室出品的Python入門教程,我是室長。

在Python中,萬物皆物件。而在我們編寫的程式碼中,實際上非常多的基本操作都是物件方法,只不過我們通常不會像一般情況下呼叫方法那樣指名道姓地呼叫這種方法。這種方法有著共同的特徵,就是方法名是以兩個下劃線開始,以兩個下劃線結束的。正因為其特殊性,這種方法得名為:魔法方法。

這裡有一點需要提前說明一下:在Python的使用中我們更多地需要了解程式執行的時機,而對於某些方法來說,我們並不需要了解它是怎麼實現的。在魔法方法的使用中,有些是需要我們自己從頭編寫的,有些則是可以從父類(或父類的父類、祖宗類,可以統稱為

超類

)繼承來並加以修飾的。在Python3中,我們可以使用super函式很方便地獲取到超類的方法。具體的程式碼我們會在後邊展示。

目前我們最熟悉的魔法方法就是__init__方法,它用來實現對一個類例項的初始化。不過__init__方法並不是一個例項生命週期的開始。在它之前還有一個建立例項的方法:__new__方法。

__new__方法:

在建立一個例項時,最先呼叫的是__new__方法來建立物件,其次才是呼叫__init__來初始化物件。

Python的魔法方法:原來是你

Python的魔法方法:原來是你

這裡我們定義了一個Lesson類,然後編寫了__new__方法。在定義那一行左邊有個小圓圈加上箭頭,這意味著我們重寫了一個超類中的方法,在執行時重寫的方法會替代掉超類中的方法。而__new__方法的第一個引數是cls,意味著這是一個類方法。後邊的*args和**kwargs可以參見

關於裝飾器的內容,因為在執行__new__方法時不知道__init__方法需要哪些引數,所以使用*args和**kwargs佔位。

我們定義的__new__方法很簡單,就是列印一行字。而在我們建立例項時,這行字也被正確地打印出來了。但是當我們想列印a的時候卻發現打印出來的是None,這是為什麼呢?因為我們雖然定義了__new__方法,但在方法裡卻沒有建立例項的程式碼,整個__new__方法的返回值是None。而真正建立一個例項並正確地初始化還是挺麻煩的,我們沒有必要從頭去寫,只要使用超類中的方法就可以了:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

__init__方法:

__init__方法是我們的老朋友了,但我們現在才瞭解到它不是例項化一個物件的第一個步驟。既然如此,我們就可以使用__init__方法在不修改物件記憶體地址的情況下對其進行重新初始化:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

需要注意的是當我們複製一個例項時,也會依次呼叫__new__方法和__init__方法。

__del__方法:

當程式中的一個物件不再被需要的時候,Python會自動地清理掉它來釋放記憶體。所以在我們看不到的地方,這種慘無人道的卸磨殺驢無時無刻不在上演。進行這種行為時會呼叫__del__方法,但這裡比較容易混淆:是進行刪除時會呼叫__del__方法,而不是呼叫__del__方法來進行刪除。因此__del__方法大概也就是個臨終遺言的作用。

Python的魔法方法:原來是你

Python的魔法方法:原來是你

可以看到如果我們直接呼叫__del__方法,並不會導致物件被刪除,而當程式結束例項沒有用時,才會被刪除,而且被刪除時還會呼叫一下__del__方法。

__str__方法和__repr__方法:

有些時候我們需要列印物件的資訊,如果我們不做一些設定的話,打印出來的是物件的型別和記憶體地址。如果我們希望打印出一些不一樣的東西,那麼可以編寫一下__str__方法和__repr__方法:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

其中__str__方法適用於直接使用print列印的情況,而__repr__方法則是在容器中打印出來時會呼叫,對於互動式直譯器(如Ipython、Jupyter Notebook等)如果直接訪問物件也會呼叫__repr_方法。另外還有一種情況就是如果沒有重寫__str__方法而只重寫了__repr__方法,那麼直接print列印時也會呼叫__repr__方法:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

反之則不然:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

__bool__方法:

在需要做bool值判斷的時候會呼叫__bool__方法,__bool__方法的返回值應當是True或False:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

__lt__方法和__gt__方法

有時候一類物件所包含的屬性是非常多的,如果我們把這樣的兩個物件直接比較,程式會不知道我們比的是什麼。在這時候我們就可以編寫__lt__方法和__gt__方法,來制定我們需要進行比較的屬性。這兩個方法在當前物件被做比較時會被呼叫。這裡lt就是less than,gt就是greater than,非常的好記:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

這裡透過編寫__lt__方法和__gt__方法將age屬性用於比較。不過因為這兩個方法在返回之前還是要進行比較,所以可能會出現一個方法呼叫另一個方法的情況。所以儘量不要在__lt__方法和__gt__方法中新增太多功能,而且要保證兩個方法中使用的屬性一致。

__eq__方法和__ne__方法:

既然可以比較大於小於自然也可以比較等於不等於,我們可以編寫__eq__方法和__ne__方法來設定判斷兩個物件是否相等的依據:

Python的魔法方法:原來是你

結果和上圖是一樣的

注意對__eq__和__ne__方法的設定屬於重寫方法。這兩個方法在返回之前還要進行當前方法中的比較,所以也不要直接新增一些額外的功能。但不同於__lt__方法和__gt__方法,他們可以設定不同的屬性作為判據。為了防止混亂,不建議這麼做。

__call__方法:

既然說python中萬物皆物件,那麼python的函式其實也是物件。而函式被呼叫時其實呼叫的是函式物件的__call__方法,只不過因為呼叫函式實在是太基本了、太頻繁了,python將其直接轉化成了函式名後加括號的形式。其實這兩種寫法的效果是一樣的

Python的魔法方法:原來是你

Python的魔法方法:原來是你

而我們在編寫一個類的時候,也可以透過編寫__call__方法來讓物件變得可呼叫:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

雖然室長沒有在這個例子中設定任何引數,但這就像任何函式一樣都是可以設定的。我們可以透過這種方法非常便捷地對物件中的屬性進行輸入、修改、輸出。

屬性操作方法:

接下來的幾個方法在我們設定、獲取以及刪除物件的屬性時會被呼叫。我們將這幾個方法整理到一起進行舉例:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

__setattr__方法

在設定物件屬性時會被呼叫,無論是初始化中的設定還是之後的修改。具體的修改方法我們直接從超類繼承就可以。

__getattribute__方法

在呼叫物件屬性時會被呼叫。不過它只管呼叫,不在乎物件有沒有被呼叫的屬性。同樣,具體的方法可以直接繼承。

__getattr__方法

防止了一個情況,那就是當我們呼叫了物件不存在的屬性時,這個方法可以讓程式不至於丟擲異常,而是直接地進入其他的操作程式碼中。

__delattr__方法

在刪除物件的某個屬性時會被呼叫。同樣,直接繼承就好。

容器操作方法:

接下來就是重磅的內容了。我們之前瞭解過的列表、元組、集合、字典等都屬於容器型別的物件,而容器型別的物件存在大量的魔法方法。我們還是將這些方法整理到一起,編寫一個“話癆”列表來給大家展示這些方法是在什麼時候被呼叫的。因為只是展示呼叫的時機,方法的實現方法我們不做展開,還是直接繼承超類方法:

Python的魔法方法:原來是你

Python的魔法方法:原來是你

__setitem__方法

會在修改元素的時候被呼叫。不過這僅限於修改元素的時候,新增元素時不會被呼叫。

__getitem__方法

會在使用索引值(對於字典來說是鍵)獲取元素時被呼叫。

__delitem__方法

會在刪除索引值對應的元素時被呼叫。需要注意的是這裡只能使用del語句進行刪除時才會被呼叫,而用pop、remove等方法則不會被呼叫。

__len__方法

會在使用len函式獲取容器長度時被呼叫。

__contains__方法

會在判斷元素是否在容器內時被呼叫。

__reversed__方法

會在將列表進行翻轉時被呼叫。

這一期我們進一步瞭解了Python中的魔法方法及其呼叫時機。這一部分內容屬於Python中比較高階的應用了,因為魔法方法涉及到一些比較基本的程式實現方式,如果我們去重新編寫魔法方法,可能會導致出現很多意想不到的問題。沒有金剛鑽別攬瓷器活,在魔法方法的使用上室長目前還是推薦使用繼承超類方法的方式。

雖然魔法方法還有很多我們沒有介紹到,但它們的泛用性與我們介紹到的方法相比要差一些,所以不再做專門的介紹了。不過除了魔法方法以外,Python中還有魔法屬性的存在,這些屬性也是以兩個下劃線為開頭和結尾的。很多時候我們透過呼叫魔法屬性可以獲得一些通常情況下不方便獲得的基礎資訊。請關注下期:

Python的魔法屬性

。如果這篇文章對你有所幫助,希望能幫室長點個

贊和在看

,你的鼓勵是室長進步的動力!