資料型別· 第1篇《元組和列表的效能分析、命名元組》
阿新 • • 發佈:2020-12-15
## 堅持原創輸出,點選藍字關注我吧
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214114911.png)
作者:清菡
部落格:oschina、雲+社群、知乎等各大平臺都有。
# 目錄
- 一、元組和列表
- 1.元組和列表的效能分析
- 2.為什麼列表在 Python 中是最常用的呢?
- 3.timeit 裡面有個 Timer 類
- 4.timeit 裡面還有個直接用的 timeit 的方法,timeit.timeit()
- 5.這 2 個方法有啥區別?
- 二、命名元組
- 三、命名元組有什麼特點?
## 一、元組和列表
![元組vs列表](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214060759.jpg)
### 1.元組和列表的效能分析
`元組和列表用來儲存資料,在元組和列表裡面查詢的時候,到底哪個更快呢?`
計算建立元組和列表所需的時間:ipython 中使用`timeit`這個命令。
**計算時間模組介紹:**
```python
import timeit
#timeit.timeit
```
可以用這個模組來測試函式的效能。
安裝 ipython:`pip install ipython`
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214062010.png)
ipython 是個互動環境,就跟我們輸入 Python 進去是一樣的。只不過它外面做了一層封裝,比 Python 互動環境更好用一點。
ipython 裡面有一個命令叫做`timeit`,後面可以跟一個 Python 表示式。
**例如定義一個列表在後面:**
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214063603.png)
敲完這行命令,返回了一行時間。這個是在記憶體中初始化一個列表,如圖可以看到建立了一千萬次,時間是 48.4ns
**可以看出,建立一個元組比建立一個列表要快得多。**
元組的速度比列表要快 3 倍多。在記憶體裡,當我們建立一個列表的時候,會劃分一塊區域出來,拿一塊區域給列表來儲存值。例如初始化,裡面給它留了 20 個位置在這個列表裡面儲存值。
![列表佔用記憶體如圖](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214072636.png)
當儲存到一定程度,Python 直譯器檢測到列表快要盛滿了的時候,它會對列表做一個擴容。
給擴容到 200,當儲存到 150 的時候,發現又快儲存滿了,又會給你繼續擴容。
**隨著資料的增多,底層會不斷給這個列表擴容。**
初始化一個元組,同樣也是一千萬次,只需 12.8ns
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214064607.png)
**元組是一個不可變的型別。**
比如定義的元組裡面有 3 個元素,Python 直譯器在給它分記憶體的時候,就給它分了 3 個格子。
這裡面只能存 3 條資料,就這麼大,所以元組佔用的記憶體比列表要少。
![元組和列表記憶體佔用對比圖](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214073620.png)
用一個列表儲存 50 條資料和用一個元組儲存 50 條資料,那麼元組佔用的記憶體要比列表小得多。
### 2.為什麼列表在 Python 中是最常用的呢?
因為列表比較靈活,用列表的話,可以往裡面不斷得新增元素。如果元素固定的,那就用元組。
### 3.timeit 裡面有個 Timer 類。
**來看看這個類的原始碼:**
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214075933.png)
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214080629.png)
`timer=default_timer`代表的是:建立一個列表、元組等,它要執行的一個次數。
**看原始碼,預設是一千萬次:**
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214080445.png)
```PYTHON
import timeit # 這個模組可以用來做效能分析
def func():
for i in range(10):
print(i)
# 這個物件有個方法叫做timeit
res = timeit.Timer(func).timeit(100) # 把這個func函式傳進去,執行100次,然後返回的是個時間
# timeit.Timer(func).timeit(100)中函式func是不需要加引號的,如果是字串、列表這些需要加
# 引號放進去
print(res)
```
可以看到執行 100 次需要的時間是:0.0043269999999999975
### 4.timeit 裡面還有個直接用的 timeit 的方法,timeit.timeit()
```PYTHON
import timeit # 這個模組可以用來做效能分析
def func():
for i in range(10):
print(i)
# 這個物件有個方法叫做timeit
# res = timeit.Timer(func).timeit(100) # 把這個func函式傳進去,執行100次,然後返回的是個時間
# timeit.Timer(func).timeit(100)中函式func是不需要加引號的,如果是字串、列表這些需要加引號放進去
# print(res)
res2 = timeit.timeit('[1,2,3]')
print(res2)
```
**這個模組的作用:** 大家寫的功能函式,可以用它測下功能函式的速度,執行大概要多久。
**預設是一千萬次,結果如下:**
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214082618.png)
**如果列表不加引號直接傳是會報錯的:**
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214083855.png)
提示不可被呼叫!
### 5.這 2 個方法有啥區別?
其實它們是一個東西。
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214084922.png)
## 二、命名元組
元組的效能是大大優於列表的。元組、列表在使用的時候,都是通過下標索引取值的。
下標索引取值不太人性化,如果我知道資料儲存在元組裡面,但是我不知道它具體儲存的下標位置。這個時候找這個元素,還得先把下標找出來,知道下標再去拿,這樣很不方便。
字典的話,這方面就比較有優勢。資料是儲存在字典裡面的,只要通過鍵,就能把值找到。字典相對於元組和列表,有一定的優勢和劣勢。
命名元組使用的時候可以讓元組像字典一樣去取值。
例如,有個元組裡面儲存了 3 條資料:
建立一個命名元組的話,需要用到 Python 的一個內建模組`from collections import namedtuple`
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214100718.png)
```PYTHON
import timeit # 這個模組可以用來做效能分析
from collections import namedtuple
# namedtuple是個函式,建立命名元組可以通過這個函式來建立
def func():
for i in range(10):
print(i)
# 這個物件有個方法叫做timeit
# res = timeit.Timer(func).timeit(100) # 把這個func函式傳進去,執行100次,然後返回的是個時間
# timeit.Timer(func).timeit(100)中函式func是不需要加引號的,如果是字串、列表這些需要加引號放進去
# print(res)
res2 = timeit.timeit('[1,2,3]')
print(res2)
# 命名元組
# 如果知道里面儲存的具體位置,可以通過下標取值。例如tu=[0]
# 如果我不知道名字儲存在哪裡,通過下標去取值就不好取了
# 命名元組可以使取值的時候像列表一樣取
student_info = namedtuple('info_tuple',['name','age','gender']) # 這個函式接收2個引數,第一個引數是建立命名元組的型別的名字;
# 第二個引數的話,傳一個列表
# 列表裡寫建立命名元組的一個命名,例如第一個元素命名為name
# 這個函式呼叫傳了2個引數,返回出來一個物件。這個物件叫做student_info
# 通過這個物件student_info建立命名元組
tu = student_info('qinghan',18,'nv')
print(tu)
```
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214100917.png)
這個 tu 就是個命名元組。
`student_info` 是通過命名元組這個`namedtuple`函式建立命名元組型別:`namedtuple('info_tuple',['name','age','gender'])`。
然後返回出來一個物件`student_info`
通過`student_info`這個物件傳入對應的元組,定義元組的時候就通過這個物件把元素寫進去,返回的就是命名元組。
## 三、命名元組有什麼特點?
它取值的時候可以像字典一樣取值,通過對應的鍵,找到對應的值。**命名元組使用起來更像物件。**
這樣用:`命名元組.name`
**這樣就能找到 name 所對應的值:**
```PYTHON
import timeit # 這個模組可以用來做效能分析
from collections import namedtuple
# namedtuple是個函式,建立命名元組可以通過這個函式來建立
def func():
for i in range(10):
print(i)
# 這個物件有個方法叫做timeit
# res = timeit.Timer(func).timeit(100) # 把這個func函式傳進去,執行100次,然後返回的是個時間
# timeit.Timer(func).timeit(100)中函式func是不需要加引號的,如果是字串、列表這些需要加引號放進去
# print(res)
res2 = timeit.timeit('[1,2,3]')
print(res2)
# 命名元組
# 如果知道里面儲存的具體位置,可以通過下標取值。例如tu=[0]
# 如果我不知道名字儲存在哪裡,通過下標去取值就不好取了
# 命名元組可以使取值的時候像列表一樣取
student_info = namedtuple('info_tuple',['name','age','gender']) # 這個函式接收2個引數,第一個引數是建立命名元組的型別的名字;
# 第二個引數的話,傳一個列表
# 列表裡寫建立命名元組的一個命名,例如第一個元素命名為name
# 這個函式呼叫傳了2個引數,返回出來一個物件。這個物件叫做student_info
# 通過這個物件student_info建立命名元組
tu = student_info('qinghan',18,'nv')
print(tu.name)
```
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214102516.png)
設定命名元組型別的時候,它返回的這個物件它裡面只包含了傳進去的這幾個名字。
接下來,要建立命名元組的時候,元素和它一樣多,名字和對應的元素的值是一一對應的,不能多,不能少。
**否則就會報錯:**
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214102859.png)
`print(type(tu)) # 看下它的型別`
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214103442.png)
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214103838.png)
它返回的物件和型別名用的同一個名字。
`print(type(student_info))`
![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201214104509.png)
```PYTHON
import timeit # 這個模組可以用來做效能分析
from collections import namedtuple
# namedtuple是個函式,建立命名元組可以通過這個函式來建立
def func():
for i in range(10):
print(i)
# 這個物件有個方法叫做timeit
# res = timeit.Timer(func).timeit(100) # 把這個func函式傳進去,執行100次,然後返回的是個時間
# timeit.Timer(func).timeit(100)中函式func是不需要加引號的,如果是字串、列表這些需要加引號放進去
# print(res)
res2 = timeit.timeit('[1,2,3]')
print(res2)
# 命名元組
# 如果知道里面儲存的具體位置,可以通過下標取值。例如tu=[0]
# 如果我不知道名字儲存在哪裡,通過下標去取值就不好取了
# 命名元組可以使取值的時候像列表一樣取
# 設定命名元組型別
# student_info是個類
student_info = namedtuple('student_info',['name','age','gender']) # 這個函式接收2個引數,第一個引數是建立命名元組的型別的名字;
# 第二個引數的話,傳一個列表
# 列表裡寫建立命名元組的一個命名,例如第一個元素命名為name
# 這個函式呼叫傳了2個引數,返回出來一個物件。這個物件叫做student_info
# 通過這個物件student_info建立命名元組
tu = student_info('qinghan',18,'nv')
print(tu.name)
print(type(tu)) # 看下它的型別
print(type(student_info))
# 因為student_info是個類,所以看student_info的type就是個type。隨便看哪個類都是一樣的。
```
--------
公眾號 **「清菡軟體測試」** 首發,更多原創文章:清菡軟體測試 105+原創文章,歡迎關注、交流,禁止第三方擅自