python不可變對象

python對象分類中已經 介紹了python不可變對象,下面將列舉實例,詳細分析:html

不可變類型(數字,字符串,元組,不可變集合):不支持原處修改。python

 

引用shell

>>> a=345  
>>> b=a >>> a is b True >>>

在python一切皆是對象,而對象是經過引用傳遞的。在賦值時,無論這個對象是新建立的,仍是一個已經存在的,都是將該對象的引用賦值給變量。故這裏a實際上和b是同一個對象,a is b爲true!緩存

 

1 數字類型(以int型爲例)

通常,嘗試修改數字對象,其實是新建一個數字對象,以下所示。app

#新建數字對象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,管理空閒空間。ui

(3)Python中的int對象就是c語言中long類型數值的擴展。spa

(4)整數對象回收時,內存並不會歸還給系統,而是將其對象的ob_type指向free_list,供新建立的對象使用。.net

>>> 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個元素:

tuple-0

當咱們把list的元素'A''B'修改成'X''Y'後,tuple變爲:

tuple-1

表面上看,tuple的元素確實變了,但其實變的不是tuple的元素,而是list的元素。tuple一開始指向的list並無改爲別的list,因此,tuple所謂的「不變」是說,tuple的每一個元素,指向永遠不變。即指向'a',就不能改爲指向'b',指向一個list,就不能改爲指向其餘對象,但指向的這個list自己是可變的!

理解了「指向不變」後,要建立一個內容也不變的tuple怎麼作?那就必須保證tuple的每個元素自己也不能變。

參考:

Python源碼--整數對象(PyIntObject)的內存池  

整數對象實現原理

python之小整數對象初探 -- 推薦博客

使用list和tuple

python引用和對象理解

python 的 tuple 是否是冗餘設計

相關文章
相關標籤/搜索