變量,對象和引用python
變量在賦值的時候建立,它能夠引用任何類型的對象,而且必須在引用以前賦值。緩存
a = 3
全部賦值操做有三個步驟:函數
在運行a=3後,變量a變成對象3的一個引用,在內部,變量其實是到對象內存空間的一個指針。spa
類型屬於對象,而不是變量指針
a = 3 a = 'spam' a = 1.23
變量名沒有類型,咱們只是把a修改成不一樣的對象的引用。所以,沒有改變a的類型,而是讓變量引用了不一樣類型的對象。code
每一個對象都包含了一個頭部信息,其中標記了這個對象的類型。對象
對象的垃圾回收blog
每當一個變量名被賦予了一個新的對象,以前那個對象佔用的空間就會被回收。這種技術叫作垃圾回收。內存
x = 42 x = 'shrubbery' x = 3.1415 x = [1, 2, 3]
在內部,python在對象中保持了一個計數器,計數器記錄了當前指向該對象的引用的數目。一旦這個計數器被設置爲零,這個對象的內存空間就會自動回收。字符串
共享引用
a = 3
b = a
a和b引用了相同的對象,指向了相同的內存空間。多個變量引用同一個對象,這叫共享引用。
a = 3 b = a a = 'spam'
這時候,b仍然引用原來的對象3。
a = 3 b = a a = a + 2
a會賦值爲一個徹底不一樣的對象,而不會影響到b。b仍是3對象。
共享引用和在原處修改
對於支持在遠處修改的對象,共享引用時須要當心,由於對一個變量名的修改會影響其餘變量。
L1 = [2, 3, 4] L2 = L1
L1[0] = 24
L1
#[24, 3, 4]
L2
#[24, 3, 4]
列表對象內的元素的遠處修改會印象程序其餘部分。若是不想要這樣的現象發生,須要python拷貝對象,而不是建立引用。拷貝列表能夠用內置列表函數,或者標準庫copy模塊,或者從頭至尾的分片。
L1 = [2, 3, 4] L2 = L1[:] L1[0] = 24 L1 #[24, 3, 4] L2 #[2, 3, 4]
共享引用和相等
x = 42 x = 'shrubbery'
由於python會緩存而且複用小的整數和小的字符串,這裏的對象42也許並不會回收,它可能會保存在一個系統表中,等待下一次代碼生成一個42來重複利用。
python中有兩種辦法檢查是否相等。看共享引用的例子:
L = [1, 2, 3] M = L L == M #True L is M #True
==操做符檢查值是否相等,is操做符,檢查對象的同一性,若是兩個變量指向同一個對象,那麼會返回True。
實際上,is比較實現引用的指針,因此這是一種檢查共享引用的方法。若是變量名的引用值相等,可是是不一樣的對象,它的返回值會是False。
L = [1, 2, 3] M = [1, 2, 3] L == M #True L is M #False
但當咱們對小的數字作一樣的操做:
x = 42 y = 42 x == y #True x is y #True
由於小的數字和字符串被緩存複用了,因此is告訴咱們它們引用的使用一個對象。
你能夠向python查詢一個對象引用的次數:在sys模塊中的getrefcount函數會返回對象的引用次數。例如,在IDLE GUI中查詢整數對象1時,會返回有837次引用。
import sys sys.getrefcount(1) #837