1. 程式人生 > >2.13 Python 賦值機制

2.13 Python 賦值機制

先看一個例子:

In [1]:

x = [1, 2, 3]
y = x
x[1] = 100
print y



[1, 100, 3]

改變變數x的值,變數y的值也隨著改變,這與Python內部的賦值機制有關。

簡單型別

先來看這一段程式碼在Python中的執行過程。

x = 500
y = x
y = 'foo'
  • x = 500

Python分配了一個 PyInt 大小的記憶體 pos1 用來儲存物件 500 ,然後,Python在名稱空間中讓變數 x 指向了這一塊記憶體,注意,整數是不可變型別,所以這塊記憶體的內容是不可變的。

記憶體 名稱空間
pos1 : PyInt(500) (不可變) x : pos1

  • y = x

Python並沒有使用新的記憶體來儲存變數 y 的值,而是在名稱空間中,讓變數 y 與變數 x 指向了同一塊記憶體空間。

記憶體 名稱空間
pos1 : PyInt(500) (不可變) x : pos1“y : pos1

  • y = ‘foo’

Python此時分配一個 PyStr 大小的記憶體 pos2 來儲存物件 foo ,然後改變變數 y 所指的物件。

記憶體 名稱空間
pos1 : PyInt(500) (不可變)pos2 : PyStr(‘foo’) (不可變) x : pos1“y : pos2

對這一過程進行驗證,可以使用 id 函式。

id(x)

返回變數 x 的記憶體地址。

In [2]:

x = 500
id(x)

Out[2]:

48220272L

In [3]:

y = x
id(y)

Out[3]:

48220272L

也可以使用 is 來判斷是不是指向同一個事物:

In [4]:

x is y

Out[4]:

True

現在 y 指向另一塊記憶體:

In [5]:

y = 'foo'
id(y)

Out[5]:

39148320L

In [6]:

x is y

Out[6]:

False

Python會為每個出現的物件進行賦值,哪怕它們的值是一樣的,例如:

In [7]:

x = 500
id(x)

Out[7]:

48220296L

In [8]:

y = 500
id(y)

Out[8]:

48220224L

In [9]:

x is y

Out[9]:

False

不過,為了提高記憶體利用效率,對於一些簡單的物件,如一些數值較小的int物件,Python採用了重用物件記憶體的辦法:

In [10]:

x = 2
id(x)

Out[10]:

6579504L

In [11]:

y = 2
id(y)

Out[11]:

6579504L

In [12]:

x is y

Out[12]:

True

容器型別

現在來看另一段程式碼:

x = [500, 501, 502]
y = x
y[1] = 600
y = [700, 800]
  • x = [500, 501, 502]

Python為3個PyInt分配記憶體 pos1 , pos2 , pos3 (不可變),然後為列表分配一段記憶體 pos4 ,它包含3個位置,分別指向這3個記憶體,最後再讓變數 x 指向這個列表。

記憶體 名稱空間
pos1 : PyInt(500) (不可變) pos2 : PyInt(501) (不可變) pos3 : PyInt(502) (不可變) pos4 : PyList(pos1, pos2, pos3) (可變) x : pos4

  • y = x

並沒有建立新的物件,只需要將 y 指向 pos4 即可。

記憶體 名稱空間
pos1 : PyInt(500) (不可變) pos2 : PyInt(501) (不可變) pos3 : PyInt(502) (不可變) pos4 : PyList(pos1, pos2, pos3) (可變) x : pos4“y : pos4

  • y[1] = 600

原來 y[1] 這個位置指向的是 pos2 ,由於不能修改 pos2 的值,所以首先為 600 分配新記憶體 pos5 。

再把 y[1] 指向的位置修改為 pos5 。此時,由於 pos2 位置的物件已經沒有用了,Python會自動呼叫垃圾處理機制將它回收。

記憶體 名稱空間
pos1 : PyInt(500) (不可變) pos2 : 垃圾回收 pos3 : PyInt(502) (不可變) pos4 : PyList(pos1, pos5, pos3) (可變)pos5 : PyInt(600) (不可變) x : pos4“y : pos4

  • y = [700, 800]

首先建立這個列表,然後將變數 y 指向它。

記憶體 名稱空間
pos1 : PyInt(500) (不可變) pos3 : PyInt(502) (不可變) pos4 : PyList(pos1, pos5, pos3) (可變)pos5 : PyInt(600) (不可變) pos6 : PyInt(700) (不可變)pos7 : PyInt(800) (不可變)pos8 : PyList(pos6, pos7) (可變) x : pos4 y : pos8

對這一過程進行驗證:

In [13]:

x = [500, 501, 502]
print id(x[0])
print id(x[1])
print id(x[2])
print id(x)



48220224
48220248
48220200
54993032

賦值,id(y) 與 id(x) 相同。

In [14]:

y = x
print id(y)



54993032

In [15]:

x is y

Out[15]:

True

修改 y[1] ,id(y) 並不改變。

In [16]:

y[1] = 600
print id(y)



54993032

id(x[1]) 和 id(y[1]) 的值改變了。

In [17]:

print id(x[1])
print id(y[1])



48220272
48220272

更改 y 的值,id(y) 的值改變

In [18]:

y = [700, 800]
print id(y)
print id(x)

54995272
54993032