python的不可變物件與可變物件及其妙用與坑

零楚L發表於2021-02-04

先上圖。

 

 圖裡,分別用三個整數進行了驗證。可以發現當a和b值相同時,a與b地址也一致。改變a的值,a的地址也跟著改變了。

原因

python的宗旨之一,萬物皆物件。(單身狗狂喜)

而物件又被分為可變物件和不可變物件。比如int,str,float,tuple都是不可變物件。所謂不可變,就是說,從實現上而言,這些物件的內容是不能更改的。雖然我們一直都可以用a=4這樣來賦值,但其實是建立了一個新的,值為4的int物件。而原本被我們賦值為3的那個a,依然存在並被賦值為3,但缺失引用之後會被python的記憶體機制進行垃圾回收。(引用計數為0,python的記憶體回收機制那一套內容)

而可變物件則是類似list,dict這樣可以改變內容的型別。它們的內容被更改時其本身地址不會改變。但注意,儲存於其中的內容又是不可變物件,所以其內容的地址有可能改變。

 

 這是緊接著上面那張圖的部分,原本e列表後兩個數為3和4時,它們共用了b和a的地址。而後修改e[2]的值後,其地址也發生了改變。但e本身的地址從未改變過。

妙用和坑

最直接的用法當然就是用於傳參了。

比如定義一個類,這個類的__init__方法需要外部的變數來初始化成員變數。

如果之後例項化之後,希望在修改物件成員變數的同時也修改外部變數,那麼就將外部變數以列表等可變物件的形式封裝。比如原本需要outer_d=0傳入為inter_d並修改同步outer_d的值,就把outer_d定義為[0],然後在內部修改inter_d[0]就能同步修改了。

而坑的也正是這裡,如果你的類或者函式,使用了array,list等作為引數,那麼就要時刻小心!是否會因為類內部方法而無意中更改了外部的變數導致bug。而如果你實在需要這樣做,我的建議是,在類內部初始化時,用一些非直接賦值的方法進行初始化!比如,重新宣告一個self.lista=[],然後用迴圈把外部列表的每一個元素挨個地給append到self.lista裡面去。因為列表內為不可變物件,所以這樣做後你怎麼修改self.lista都不會無意觸碰到外部變數了!

相關文章