目錄前端
列表和元組,都是一個能夠放置任意數據類型的有序集合。
在絕大多數語言中,集合的數據類型必須一致。不過對於python中的列表和來講沒有這樣的要求python
列表是動態的,長度大小不固定,能夠隨意增刪改。
元組是靜態的,長度大小固定,沒法增刪改。git
先看一個例子github
l = [1, 2, 3] l.__sizeof__() # 64 tup = (1, 2, 3) tup.__sizeof__() # 48
你能夠看到,對列表和元組,咱們放置了相同的元素,可是元組的存儲空間,卻比列表要少 16 字節。這是爲何呢?數據庫
事實上,因爲列表是動態的,因此它須要存儲指針,來指向對應的元素(上述例子中,對於 int 型,8 字節)。另外,因爲列表可變,因此須要額外存儲已經分配的長度大小(8 字節),這樣才能夠實時追蹤列表空間的使用狀況,當空間不足時,及時分配額外空間。緩存
l = [] l.__sizeof__() # 空列表的存儲空間爲 40 字節 # 40 l.append(1) l.__sizeof__() # 72 # 加入了元素 1 以後,列表爲其分配了能夠存儲 4 個元素的空間 (72 - 40)/8 = 4 l.append(2) l.__sizeof__() # 72 # 因爲以前分配了空間,因此加入元素 2,列表空間不變 l.append(3) l.__sizeof__() # 72 # 同上 l.append(4) l.__sizeof__() # 72 # 同上 l.append(5) l.__sizeof__() # 104 # 加入元素 5 以後,列表的空間不足,因此又額外分配了能夠存儲 4 個元素的空間
上面的例子,大概描述了列表空間分配的過程。咱們能夠看到,爲了減少每次增長 / 刪減操做時空間分配的開銷,Python 每次分配空間時都會額外多分配一些,這樣的機制(over-allocating)保證了其操做的高效性:增長 / 刪除的時間複雜度均爲 O(1)。app
可是對於元組,狀況就不一樣了。元組長度大小固定,元素不可變,因此存儲空間固定。函數
看了前面的分析,你也許會以爲,這樣的差別能夠忽略不計。可是想象一下,若是列表和元組存儲元素的個數是一億,十億甚至更大數量級時,你還能忽略這樣的差別嗎?oop
經過學習列表和元組存儲方式的差別,咱們能夠得出結論:元組要比列表更加輕量級一些,因此整體上來講,元組的性能速度要略優於列表。性能
另外,Python 會在後臺,對靜態數據作一些資源緩存(resource caching)。一般來講,由於垃圾回收機制的存在,若是一些變量不被使用了,Python 就會回收它們所佔用的內存,返還給操做系統,以便其餘變量或其餘應用使用。
可是對於一些靜態變量,好比元組,若是它不被使用而且佔用空間不大時,Python 會暫時緩存這部份內存。這樣,下次咱們再建立一樣大小的元組時,Python 就能夠不用再向操做系統發出請求,去尋找內存,而是能夠直接分配以前緩存的內存空間,這樣就能大大加快程序的運行速度。
下面的例子,是計算初始化一個相同元素的列表和元組分別所需的時間。咱們能夠看到,元組的初始化速度,要比列表快 5 倍。
python3 -m timeit 'x=(1,2,3,4,5,6)' 20000000 loops, best of 5: 9.97 nsec per loop python3 -m timeit 'x=[1,2,3,4,5,6]' 5000000 loops, best of 5: 50.1 nsec per loop
但若是是索引操做的話,二者的速度差異很是小,幾乎能夠忽略不計。
python3 -m timeit -s 'x=[1,2,3,4,5,6]' 'y=x[3]' 10000000 loops, best of 5: 22.2 nsec per loop python3 -m timeit -s 'x=(1,2,3,4,5,6)' 'y=x[3]' 10000000 loops, best of 5: 21.9 nsec per loop
固然,若是你想要增長、刪減或者改變元素,那麼列表顯然更優。緣由你如今確定知道了,那就是對於元組,你必須得經過新建一個元組來完成。
那麼列表和元組到底用哪個呢?根據上面所說的特性,咱們具體狀況具體分析。
def get_location(): ..... return (longitude, latitude)
viewer_owner_id_list = [] # 裏面的每一個元素記錄了這個 viewer 一週內看過的全部 owner 的 id records = queryDB(viewer_id) # 索引數據庫,拿到某個 viewer 一週內的日誌 for record in records: viewer_owner_id_list.append(record.id)
關於列表和元組,咱們今天聊了不少,最後一塊兒總結一下你必須掌握的內容。
總的來講,列表和元組都是有序的,能夠存儲任意數據類型的集合,區別主要在於下面這兩點。
列表是動態的,長度可變,能夠隨意的增長、刪減或改變元素。列表的存儲空間略大於元組,性能略遜於元組。
元組是靜態的,長度大小固定,不能夠對元素進行增長、刪減或者改變操做。元組相對於列表更加輕量級,性能稍優。
empty_list = list() # 方式一 empty_list = [] # 方式二 """ 區別主要在於list()是一個函數調用,Python的function call會建立stack, 而且進行一系列參數檢查的操做,比較expensive,反觀[]是一個內置的C函數, 能夠直接被調用,所以效率高。 """
list和tuple的內部實現都是array的形式,list由於可變,因此是一個over-allocate的array,tuple由於不可變,因此長度大小固定。具體能夠參照源碼
list: https://github.com/python/cpython/blob/master/Objects/listobject.c.
tuple: https://github.com/python/cpython/blob/master/Objects/tupleobject.c