列表和元組

差別

共同點

列表和元組,都是一個能夠放置任意數據類型的有序集合。
在絕大多數語言中,集合的數據類型必須一致。不過對於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

固然,若是你想要增長、刪減或者改變元素,那麼列表顯然更優。緣由你如今確定知道了,那就是對於元組,你必須得經過新建一個元組來完成。

列表和元組的使用場景

那麼列表和元組到底用哪個呢?根據上面所說的特性,咱們具體狀況具體分析。

  1. 若是存儲的數據和數量不變,好比你有一個函數,須要返回的是一個地點的經緯度,而後直接傳給前端渲染,那麼確定選用元組更合適。
def get_location():
    ..... 
    return (longitude, latitude)
  1. 若是存儲的數據或數量是可變的,好比社交平臺上的一個日誌功能,是統計一個用戶在一週以內看了哪些用戶的帖子,那麼則用列表更合適。
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

相關文章
相關標籤/搜索