物件與記憶體管理


在Python中所有東西都是物件,即使是數值型態也不例外,變數在Python中,是個用來參考至物件的名稱。例如:
>>> x = 1.0
>>> y = 1.0
>>> id(x)
25925072
>>> id(y)
25925056
>>> x == y
True
>>> x is y
False
>>> x = y
>>> id(x)
25925056
>>> id(y)
25925056
>>> x is y
True
>>>


在上例中,x與y一開始分別參考至兩個浮點數物件,可以使用id()函式來傳回物件所在的記憶體位址值。==在Python中比較實質的相等性,如果要知道兩個變數是否參考至同一物件,則可以使用is運算子。指定運算會將右邊物件指定給左邊變數參考,在上例中,y參考的物件後來指定了給x參考,而x原先參考的物件,目前沒有任何變數參考至它,最後就會被垃圾回收(Garbage collection),從記憶體中清除。

+在Python中通常會產生新物件,例如在串接字串時:
>>> str1 = 'Just'
>>> str2 = 'in'
>>> str3 = str1 + str2
>>> str3
'Justin'
>>> id(str3)
26577760
>>> str3 = str1 + str2
>>> id(str3)
26578432
>>> str3 = str1 + str2
>>> id(str3)
26577760
>>>


在上例中可以看到,每次串接都會產生新字串,因此str3所參考的物件記憶體位址都不相同,在Python中不建議在經常性的操作中使用+串接字串(例如迴圈中)。如果要串接字串,可以一些替代方式,例如先使用串列收集:
>>> str1 = 'Just'
>>> str = ''
>>> id(str)
25608320
>>> str += 'Just'
>>> id(str)
26606976
>>> str += 'in'
>>> id(str)
26578432
>>> str
'Justin'
>>> buf = []
>>> id(buf)
27053752
>>> buf.append('Just')
>>> id(buf)
27053752
>>> buf.append('in')
>>> id(buf)
27053752
>>> str = ''.join(buf)
>>> str
'Justin'
>>>


上例中,示範了直接使用+與使用串列先收集個別字串的方式,如果執行次數頻繁的話,後者會較有效率。

在Python中,對於小整數或字串會有快取的動作。例如:
>>> x = 1
>>> y = 1
>>> id(1)
505389048
>>> x = 1
>>> y = 1
>>> id(x)
505389048
>>> id(y)
505389048
>>> x = 10000
>>> y = 10000
>>> id(x)
26713152
>>> id(y)
26711664
>>> str1 = 'Justin'
>>> str2 = 'Justin'
>>> str1 == str2
True
>>>


什麼範圍的小整數會快取,因Python的版本而有所不同。

如果想要知道一個物件有幾個名稱參考至它,可以使用sys.getrefcount()函式。例如:
>>> import sys
>>> sys.getrefcount(1)
117
>>> x = [1, 2, 3]
>>> y = x
>>> z = x
>>> sys.getrefcount(x)
4