在python對象分類中已經 介紹了python不可變對象,下面將列舉實例,詳細分析:
不可變類型(數字,字符串,元組,不可變集合):不支持原處修改。
引用
>>> a=345 >>> b=a >>> a is b True >>>
在python一切皆是對象,而對象是通過引用傳遞的。在賦值時,不管這個對象是新創建的,還是一個已經存在的,都是將該對象的引用賦值給變量。故這里a實際上和b是同一個對象,a is b為true!
1 數字類型(以int型為例)
一般,嘗試修改數字對象,實際上是新建一個數字對象,如下所示。
#新建數字對象1000 >>> id(1000) 53060472L #新建數字對象1000 >>> y = 1000 >>> id(y) 53060328L #嘗試操作修改數字對象,實際上生成新的數字對象 >>> y = y + 1 >>> y 1001 >>> id(y) 53058744L
(1)但有一個特例,對於小整數[-5, 256]。考慮到小整數可能頻繁使用,出於性能考慮,Python使用小整數對象緩沖池small_ints
緩存了[-5,257)之間的整數,該范圍內的整數在Python系統中是共享的。小整數對象在py啟動過程中初始化,這些個小整數對象的ob_refcnt不會改變且永遠>0,所以在vm運行過程中不會被銷毀,所以起到了緩沖的作用。
(2)對於超出了[-5, 257)之間的其他整數,Python同樣提供了專門的緩沖池(通用整數對象的緩沖池),供這些所謂的大整數使用,避免每次使用的時候都要不斷的malloc分配內存帶來的效率損耗。通過free-list,管理空閑空間。
(3)Python中的int對象就是c語言中long類型數值的擴展。
(4)整數對象回收時,內存並不會歸還給系統,而是將其對象的ob_type指向free_list,供新創建的對象使用。
>>> x = -5 >>> id(x) 8676152L >>> y = -5 >>> id(y) 8676152L >>> x = -6 >>> id(x) 53060472L >>> y = -6 >>> id(y) 53059080L >>> x = 200 >>> id(x) 8681192L >>> y = 200 >>> id(y) 8681192L
2 字符串類型
比如對於不可變對象str,進行操作:
>>> a = 'abc' >>> id(a) 52053576L #引用新生成的對象 >>> b = a.replace('a','A') >>> id(b) 47950704L >>> id(a) 52053576L >>> b 'Abc'
要始終牢記的是,a
是變量,而'abc'
才是字符串對象!有些時候,我們經常說,對象a
的內容是'abc'
,但其實是指,a
本身是一個變量,它指向的對象的內容才是'abc'
:
當我們調用a.replace('a', 'A')
時,實際上調用方法replace
是作用在字符串對象'abc'
上的,而這個方法雖然名字叫replace
,但卻沒有改變字符串'abc'
的內容。相反,replace
方法創建了一個新字符串'Abc'
並返回,如果我們用變量b
指向該新字符串,就容易理解了,變量a
仍指向原有的字符串'abc'
,但變量b
卻指向新字符串'Abc'
了:
所以,對於不變對象來說,調用對象自身的任意方法,也不會改變該對象自身的內容。相反,這些方法會創建新的對象並返回,這樣,就保證了不可變對象本身永遠是不可變的。
而對可變對象(e.g list)進行操作時,會改變對象自身的內容(in-place change)。
>>> list1 = [6, 1, 5] >>> id(list1) 55271368L >>> list1.append(2) >>> id(list1) 55271368L
3 tuple(元組)
當你定義一個tuple時,在定義的時候,tuple的元素就必須被確定下來。
最后來看一個“可變的”tuple:
>>> t = ('a', 'b', ['A', 'B'])
>>> t
('a', 'b', ['A', 'B'])
>>> hash(t)
Traceback (most recent call last):
File "<pyshell#179>", line 1, in <module>
hash(t)
TypeError: unhashable type: 'list'
>>> t[2][0] = 'X' >>> t[2][1] = 'Y' >>> t ('a', 'b', ['X', 'Y'])
這個tuple定義的時候有3個元素,分別是'a'
,'b'
和一個list。不是說tuple一旦定義后就不可變了嗎?怎么后來又變了?
別急,我們先看看定義的時候tuple包含的3個元素:
當我們把list的元素'A'
和'B'
修改為'X'
和'Y'
后,tuple變為:
表面上看,tuple的元素確實變了,但其實變的不是tuple的元素,而是list的元素。tuple一開始指向的list並沒有改成別的list,所以,tuple所謂的“不變”是說,tuple的每個元素,指向永遠不變。即指向'a'
,就不能改成指向'b'
,指向一個list,就不能改成指向其他對象,但指向的這個list本身是可變的!
理解了“指向不變”后,要創建一個內容也不變的tuple怎么做?那就必須保證tuple的每一個元素本身也不能變。
參考:
Python源碼--整數對象(PyIntObject)的內存池
python之小整數對象初探 -- 推薦博客