Python的每個對象都分為可變和不可變,主要的核心類型中否彩,數(shù)字疯攒、字符串、元組是不可變的列荔,列表敬尺、字典是可變的枚尼。
對不可變類型的變量重新賦值,實際上是重新創(chuàng)建一個不可變類型的對象砂吞,并將原來的變量重新指向新創(chuàng)建的對象(如果沒有其他變量引用原有對象的話(即引用計數(shù)為0)署恍,原有對象就會被回收)。
不可變類型
以int類型為例:實際上i += 1
并不是真的在原有的int
對象上+1
呜舒,而是重新創(chuàng)建一個value
為6
的int
對象锭汛,i
引用自這個新的對象笨奠。
>>> i = 5
>>> i += 1
>>> i
6
通過id函數(shù)查看變量i
的內(nèi)存地址進行驗證(使用hex(id(i))
可以查看16進制的內(nèi)存地址)
>>> i = 5
>>> i += 1
>>> i 6
>>> id(i)
140243713967984
>>> i += 1
>>> i 7
>>> id(i)
140243713967960
可以看到執(zhí)行i += 1
時袭蝗,內(nèi)存地址都會變化,因為int
類型是不可變的般婆。
再改改代碼到腥,但多個int
類型的變量值相同時,看看它們內(nèi)存地址是否相同蔚袍。
>>> i = 5
>>> j = 5
>>> id(i)
140656970352216
>>> id(j)
140656970352216
>>> k = 5
>>> id(k)
140656970352216
>>> x = 6
>>> id(x)
140656970352192
>>> y = 6
>>> id(y)
140656970352192
>>> z = 6
>>> id(z)
140656970352192
對于不可變類型int
乡范,無論創(chuàng)建多少個不可變類型,只要值相同啤咽,都指向同個內(nèi)存地址晋辆。同樣情況的還有比較短的字符串。
對于其他類型則不同宇整,以浮點型
為例瓶佳,從代碼運行結(jié)果可以看出它是個不可變
類型:對i
的值進行修改后,指向新的內(nèi)存地址鳞青。
>>> i = 1.5
>>> id(i)
140675668569024
>>> i = i + 1.7
>>> i 3.2
>>> id(i)
140675668568976
修改代碼聲明兩個相同值的浮點型
變量霸饲,查看它們的id,發(fā)現(xiàn)它們并不是指向同個內(nèi)存地址臂拓,這點和int
類型不同(這方面涉及Python內(nèi)存管理機制厚脉,Python對int
類型和較短的字符串
進行了緩存,無論聲明多少個值相同的變量胶惰,實際上都指向同個內(nèi)存地址傻工。)。
>>> i = 2.5
>>> id(i)
140564351733040
>>> j = 2.5
>>> id(j)
140564351733016
可變類型
的話孵滞,以list
為例精钮。list
在append
之后,還是指向同個內(nèi)存地址剃斧,因為list
是可變類型轨香,可以在原處修改。
>>> a = [1, 2, 3]
>>> id(a)
4385327224
>>> a.append(4)
>>> id(a)
4385327224
改改代碼幼东,當存在多個值相同的不可變
類型變量時臂容,看看它們是不是跟可變類型一樣指向同個內(nèi)存地址
>>> a = [1, 2, 3]
>>> id(a)
4435060856
>>> b = [1, 2, 3]
>>> id(b)
4435102392
從運行結(jié)果可以看出科雳,雖然a
、b
的值相同脓杉,但是指向的內(nèi)存地址不同糟秘。我們也可以通過b = a
的賦值語句,讓他們指向同個內(nèi)存地址:
>>> a = [1, 2, 3]
>>> id(a)
4435060856
>>> b = [1, 2, 3]
>>> id(b)
4435102392
>>> b = a
>>> id(b)
4435060856
這個時候需要注意球散,因為a
尿赚、b
指向同個內(nèi)存地址,而a
蕉堰、b
的類型都是List
凌净,可變類型,對a
屋讶、b
任意一個List
進行修改冰寻,都會影響另外一個List
的值。
>>> b.append(4)
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
>>> id(a)
4435060856
>>> id(b)
4435060856
代碼中皿渗,b
變量append(4)
斩芭,對a
變量也是影響的。輸出他們的內(nèi)存地址乐疆,還是指向同個內(nèi)存地址划乖。