天天看點

讀懂python中的self

  在Python類中規定,函數的第一個參數是執行個體對象本身,無論是顯式建立類的構造方法,還是向類中添加執行個體方法,都要求将 self 參數作為方法的第一個參數,并且約定俗成,把其名字寫為self。例如定義一個Chinese類:

  但Python中并沒有規定該參數的具體名稱,之是以将其命名為 self,隻是程式員之間約定俗成的一種習慣,遵守這個約定,可以使我們編寫的代碼具有更好的可讀性(大家一看到 self,就知道它的作用)。

從執行個體與類關系來說

  self 參數的具體作用是什麼呢?打個比方,如果把類比作造房子的圖紙,那麼類執行個體化後的對象是真正可以住的房子。根據一張圖紙(類),我們可以設計出成千上萬的房子(類對象),每個房子長相都是類似的(都有相同的類變量和類方法),但它們都有各自的主人,那麼如何對它們進行區分呢?

  當然是通過 self 參數,它就相當于每個房子的門鑰匙,可以保證每個房子的主人僅能進入自己的房子(每個類對象隻能調用自己的類變量和類方法)。

  也就是說同一個類可以産生多個對象,當某個對象調用類方法時,該對象會把自身的引用作為第一個參數自動傳給該方法,換句話說,Python 會自動綁定類方法的第一個參數指向調用該方法的對象。如此,Python解釋器就能知道到底要操作哪個對象的方法。

  是以得出結論:無論是建立類的構造方法還是執行個體方法,最少要包含一個參數self。

  通過執行個體的self參數與對象進行綁定,程式在調用執行個體方法和構造方法時,也不需要手動為第一個參數傳值。是以我們在調用成員方法時可以寫成:

從執行個體方法存儲記憶體空間來講

讀懂python中的self

  對象在執行個體化的時候,構造函數會開辟一塊記憶體空間,把屬性存到DY那個對象那裡,執行個體方法還是存儲在類的方法區,對象直接去引用就行,原因在于copy出來函數執行代碼效果是不變的。執行個體化出來的對象如果想調用類的方法,就需要到Chinese類中去取。

  但有個問題,如果不告訴類是誰在調用執行個體方法,那麼調用方法産生的結果不知道傳回給哪個對象。是以我們在調用Chinese. talk(self)的時候應該告訴類是哪個對象在調用,是以最簡單的辦法是把對象傳進去。那麼調用執行個體方法時還可以寫成:

是以在調用執行個體方法時,都需要把self代表的對象傳進去,是以這個self就是誰調用這個方法,表示的就是哪個對象。

上面說到類的執行個體方法(函數)中一定要有傳入一個參數self,把執行個體方法與調用該方法的對象進行綁定,那麼怎麼證明self指的就是該對象呢?

通過執行結果我們可以看出:

①列印對象DY傳回的結果

②調用執行個體方法DY.talk()與zhang.talk()列印出self的記憶體位址分别為0x000001C718A1DA88和0x000001C718A1FF08,也就是說不同執行個體方法self的并不是同一個對象,DY.talk()中self指的是DY對象,zhang.talk()中self指的是zhang對象。

綜合以上得出:self指的是實際調用該方法的對象。

上面代碼self更改為this:

  改成this後,運作結果完全一樣。我們隻是使用self代指調用方法的對象,完成對象和執行個體方法的第一個參數進行綁定,至于執行個體方法的第一個參數寫成a,b,c.....或者this完全不受影響。

當然,最好還是尊重約定俗成的習慣,使用self。

我們試下執行個體方法(函數)中不傳入參數self:

  執行結果的意思是:TypeError: talk()接受0個位置參數,但給出了1個。但是我們在調用執行個體方法的時候并沒有給函數傳入參數,給出的這1個參數是哪裡來的?

  上面我們有說到執行個體方法與類的靜态屬性(執行個體變量)不同,執行個體變量會在執行個體化對象時存儲在對象的記憶體區間,但執行個體方法是存儲在類的方法區,隻有執行個體方法被調用的時候才會被加載,是以我們在執行DY.talk()時,Python解釋器解釋為Chinese.talk(DY),把self替換成類的執行個體,這樣就解釋了上面的問題,給出的這一個位置參數就是self,也就是調用方法的對象。

是以,執行個體方法中必須要傳入一個形參,不可以不寫self。

  類中的變量分為類變量、執行個體變量、局部變量。類變量就是定義在方法(函數)外的變量,在方法中可以使用類名進行調用,在類方法中可以使用cls.變量名進行調用,相對來說好做區分。執行個體變量和局部變量都是存在于方法中(函數内),那麼大家肯定會有個疑問:變量前什麼時候加self(執行個體變量),什麼時候不加self(局部變量)?或者為了以防萬一變量前全都加self,如下:

  但這樣很明顯沒有意義,url/resp/text/status這些變量都是局部的,别的方法裡面不需要通路這些變量,隻存在于test_login函數中,别的用例也不需要使用這些變量,是以除了session屬性需要共用以外,其他變量前不需要加self。

  我們隻需記住:字首帶self的變量,就是在整個類的代碼塊裡面類似是作為全局變量,如果變量前面加了self,那麼在任何執行個體方法(非staticmethod和calssmethod)就都可以通路這個變量了,如果沒有加self,隻有在目前函數内部才能通路這個變量。

self在定義執行個體方法時需要傳入該參數,但是在調用時會自動傳入。

self的名字并不是規定死的,但是最好還是按照約定是用self。

self總是指調用該方法的執行個體。

執行個體方法中需要在全局引用的變量需要加字首self。