1. 程式人生 > >python物件的引用特徵和可變性

python物件的引用特徵和可變性

物件的身份,相等性和別名

先看一個例子:

>>> a = [1,2,3,4]
>>> b = a
>>> b is a
True
>>> id(a),id(b)
(58065824, 58065824)
>>> a.append(5)
>>> a
[1, 2, 3, 4, 5]
>>> b
[1, 2, 3, 4, 5]
>>> 

(1)這裡的b就是a的一個別名(alias)

(2)所以is返回true,id()函式對a和b返回的值也是相同的

(3)針對a的修改也同時修改了b

繼續:

>>> c = [1,2,3,4,5]
>>> c == a
True
>>> c is a
False
>>> 

(1)這裡的c的值與a相等,所以==返回True

(2)但是c不是a的別名,它們的id不同

它們在記憶體中的資料模型如下圖所示:

這裡寫圖片描述

為什麼會有上面的不同呢?

其實,在python手冊中的資料模型解釋中有這麼一段話:

Every object has an identity, a type and a value. An object’s identity never changes once
it has been created; you may think of it as the object’s address in memory. The is

operator
compares the identity of two objects; the id() function returns an integer representing its identity.

主要意思:

(1) 每個物件都有一個唯一的id,(CPython中id就是物件在記憶體中的地址),且在建立的時候確定,以後不再改變;

(2) is比較是比較兩個物件的id;

(3) id()函式返回的是一個整形的物件id;

上面的例子中c是一個新建立的物件,雖然內容和a一樣,但是id是不同的,所以is返回的是False,而b僅僅是a的一個別名,相當於C++中的引用,b和a在記憶體中的地址是一樣的,是同一個物件,所以is返回True。至於c和a的==比較返回True,下面會繼續解釋。

何時選擇is,何時用==

==操作符比較的是物件的內容,而is比較的是物件的id。

==操作符在比較的時候其實是呼叫了物件的.eq()函式, a == b其實是呼叫了a.eq(b)的結果。這也就是為什麼is會比==快的原因。

元組(tuple) 不變性的一個陷阱

元組(tuple)和其他容器型別一樣,存放的都是物件的引用,元組是不可改變的,但是如果它的元素是可變型別的,那麼它還是可以被改變的。下面的例子可以說明:

>>> t1= (1,2,[3,4])
>>> t1[-1].append(5)
>>> t1
(1, 2, [3, 4, 5])
>>>

這裡寫圖片描述

這裡寫圖片描述

在看如下操作,
t1[2] += [6,7]
這個會發生什麼呢?

>>> t1[2] += [6,7]
Traceback (most recent call last):
  File "<pyshell#25>", line 1, in <module>
    t1[2] += [6,7]
TypeError: 'tuple' object does not support item assignment
>>> t1
(1, 2, [3, 4, 5, 6, 7])

可以看到,丟擲了異常,這很好理解,tuple是不可變的,針對tuple元素的賦值會丟擲TypeError異常。但是這裡的t1中的列表元素還是變了,再看下執行前後的狀態。

這裡寫圖片描述

這裡寫圖片描述