1. 程式人生 > >【python】可變物件與非可變物件

【python】可變物件與非可變物件

在Python中任何物件都有的三個通用屬性:唯一標識,型別,值。

唯一標識:用於標識物件的在記憶體中唯一,它在物件建立之後就不會再,函式可以檢視物件的唯一標識 id()

型別:決定了該物件支援哪些操作,不同型別的物件支援的操作就不一樣,比如列表可以有長度屬性,而整數沒有同樣地物件的型別一旦確定了就不會再變,函式可以報道檢視物件的型別資訊。 type()

物件與唯一標識不一樣,並不是所有的物件的值都是一成不變的,有些物件的值可以通過某些操作發生改變,值可以變化的物件稱之為可變物件(可變),值不能改變的物件稱之為不可變物件(不可變)

不可變物件:對於不可變物件,值永遠是剛開始建立時候的值,對該物件做的任何操作都會導致一個新的物件的建立。常見的不可變物件有:int,float,tuple, set, str

可變物件:可變物件的值可以通過某些操作動態的改變,比如列表物件,可以通過append方法不斷地往列表中新增元素,該列表的值就在不斷的處於變化中,一個可變物件賦值給兩個變數時,他們共享同一個例項物件,指向相同的記憶體地址,對其中任何一個變數操作時,同時也會影響另外一個變數。常見的可變物件有list,dict。

舉例1:賦值語句


說明:x=6. 左邊的是指向,右邊的是一個物件(物件)或者一個有指向物件的指向,可以有多個指向指向同一個物件(物件),[注意此地物件的意思,可以是值,例項,函式等等],綜上,此地時建立了一個叫x的變數(變數)

上面操作的物件是不可變物件.b = a,可以表示a和b都指向整型1,即他們有相同的地址,當a = 2時,由於a是補課班變數a=2改變了a的值就相當於改變了a的指向的地址。而b指向的地址還是要原來整型1的地址,即此時a!=b。

下面對比下可變物件:


可以看到此時一個和b的值一樣,由於a和b都是同一地址,當a為可變數時,a的值發生改變時是在原地址上的值改變了,所以結果a和b最後還是相同的。

舉例2:自加語句 (a+=1與a=a+1是否真的一樣)


上面可以看出L2+ =1與L2 = L2 + 1會產生不同的結果,雖然值相同但是已經是不同的物件了

講到上面的不同原因先來看看__add__和__iadd__ 的區別

  • __add__方法接收兩個引數,返回它們的和,兩個引數的值均不會改變。

  • __iadd__方法同樣接收兩個引數,但它是屬於in-place操作,就是說它會改變第一個引數的值,因為這需要物件是可變的,所以對不可變物件沒有__iadd__方法。

+=  首先操作會嘗試呼叫物件的  __iadd__ 方法,如果沒有該方法,嘗試那麼呼叫 __add__ 方法。

但是整數物件沒有__iadd方法,而列表物件提供了__iadd__方法。

程式碼L2 + = [3]操作呼叫了--iadd__方法,他會原地址的修改L2的指向的那個物件本身的值

如下圖所示:此時L1和L2還是指向同一個物件

但是程式碼L2 = L2 + [3]中的操作是呼叫的是__add__方法,該方法會返回一個新的物件,原來的物件保持不變,L1還是指向原來的物件,L2卻指向了一個新的物件。

如下圖所示:

以上就是表示式i + = x與i = i + x的區別。因此對於列表進行+ =操作時,會存在潛在的bug,因為l1會因為l2的變化而發生改變,就像函式的引數不宜使用可變物件作為關鍵字引數一樣。

注:因為整型沒有__iadd__方法,所以不管是a=1,a+=1還是a=a+1,最終結果都是用方法__add__,結果都是指向新的物件。


參考:https //mp.weixin.qq.com/s/jluii9YIvfhKd_tPecfTaw