[Python] list vs tupple
阿新 • • 發佈:2020-07-04
# 前言
列表(list)和 元組(tupple) 是 Python 中常見的兩種資料結構.這兩者使用方法有一定的相似,倆者都是 Python 內建型別,都可以儲存資料集合,都可以儲存複合資料,我們同樣可以通過索引去訪問它們.
那麼問題來了,倆者究竟有區別嗎???
# list 和 tupple 的區別
首先回答問題.list 和 tupple 有區別嗎?答案是肯定的,兩者有區別. list 和 tupple 的本質區別在於,前者是一個可變物件而後者是一個不可變物件。
什麼是可變物件和不可變物件呢?**簡單地來說,可變物件就是建立之後可以修改,而不可變物件則是建立之後不允許在修改。**
![](https://img2020.cnblogs.com/blog/627405/202007/627405-20200704080357206-1128037820.png)
沒關係,讓我們看一下例子
首先建立一個 `list`
```python
>>> a = ["a","b","c","d"]
```
接著我們試著修改一下上面的 `list` , 將 `b` 改成 `e`,看看會發生什麼
```python
>>> a[1] = "e"
>>> a
['a', 'e', 'c', 'd']
```
好像什麼都沒有發生~~
沒關係,我們再來建立一個 `tupple`
```python
>>> b=("a","b","c","d")
```
同樣地,讓我們將 `tupple` 中的 `b` 改成 `e`
```python
>>> b[1]="2"
Traceback (most recent call last):
File "", line 1, in
TypeError: 'tuple' object does not support item assignment
```
為什麼同樣的賦值操作,在 `tupple` 中會出現錯誤呢?原因就是我們上面說到的 **`tupple` 是不可變物件,建立之後不能修改**。
有個小夥伴看見了
![](https://img2020.cnblogs.com/blog/627405/202007/627405-20200704080423251-768050157.png)
然後給我寫了一段下面的程式碼
```python
>>> b=("a","b","c","d")
>>> b=("a","e","c","d")
>>>b
>>>("a","e","c","d")
```
這樣子是不是做到了修改 `tupple` 中的第2個元素呢?答案是否定的,為什麼呢?彆著急往下看
# 可變物件和不可變物件
在開始下面的內容之前,需要牢記一句話,**Python 中的變數是對在記憶體中 Python 物件的引用**
以我們上面的列表 `a` 為例
```python
>>> a = ["a","b","c","d"]
```
它在記憶體中實際表現如下圖
![](https://img2020.cnblogs.com/blog/627405/202007/627405-20200704080431674-316985774.png)
如果需要獲取列表 `list` 在記憶體的實際位置,我們可以借用內建函式 `id()`
```python
>>> a=["a","b","c","d"]
>>> id(a)
4557552456
```
現在我們去修改一下 a[1] 的值,然後再用 `id()` 這個函式去獲取 a 在記憶體的地址,你會發現它的值沒有改變,仍然指向相同位置
```python
>>> a[1] = "e"
>>> id(a)
4557552456
```
整個過程如下圖
![](https://img2020.cnblogs.com/blog/627405/202007/627405-20200704080459712-2033887495.png)
接下來我們看一下對 `tupple` 進行同樣的操作會有什麼變化
```python
>>> a=("a","b","c","d")
>>> id(a)
4557412296
>>> a=("a","e","c","d")
>>> id(a)
4557586504
```
不難發現,再修改之後指向記憶體中的地址發生了改變,這意味著這個時候變數 `a` 指向了一個全新的物件。
如果覺得難以理解,沒有關係,看下面的圖
![](https://img2020.cnblogs.com/blog/627405/202007/627405-20200704080506179-9711428.png)
這個時候如果沒有其它變數指向之前的 `tupple`,Python 的 GC 將會把舊的 `tupple` 從記憶體中完全刪除.
# 為什麼需要 list 和 tupple ?
其實更貼切的應該問,為什麼需要可變物件和不可變物件呢?
1. 新增元素效率
從上面的內容,我們知道一旦建立了 tupple,這個時候任何修改操作都會去建立新的物件,然後變數重新指向新的物件,假設新增的元素足夠多,其效率可想而知。這裡的新增是指如下的操作( tupple 本身沒有新增的方法)
```python
a = ()
for i in range(num):
a = a + (i,)
```
2. debugger 難度
在之前的 [直接賦值,深拷貝和淺拷貝] 中提到可變物件,修改賦值後的變數,會對原有的變數造成影響,會導致其 `value` 值的改變,在實際開發過程中很容易被忽略
```python
>>> a = [1, 3, 5, 7]
>>> b = a
>>> b[0] = -10
>>> a
[-10, 3, 5, 7]
```
# 什麼時候去使用 tupple 和 list
總結一下,list 和 tupple 的使用場景
1. tupple 不存在新增和刪除的操作,更不存在修改的操作,如果有這些需求,不用使用 tupple,去用 list
2. 如果只是遍歷的話, tupple 的速度是比 list 要快的
3. 如果你有些資料是需要防寫,不希望在執行過程中被修改的話,用 tupple
4. tupple 可以用來做 dict 的 key 的,準確的說,所有不可變物件都可以,而 list 不可以
# 參考
https://learnbatta.com/blog/why-tuple-is-faster-than-list-in-python-22/
https://www.afternerd.com/blog/difference-between-list-tuple/
https://www.programiz.com/python-programming/list-vs