1. 程式人生 > >資料型別· 第1篇《元組和列表的效能分析、命名元組》

資料型別· 第1篇《元組和列表的效能分析、命名元組》

## 堅持原創輸出,點選藍字關注我吧 ![](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+原創文章,歡迎關注、交流,禁止第三方擅自