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

清菡發表於2020-12-15

堅持原創輸出,點選藍字關注我吧

作者:清菡
部落格:oschina、雲+社群、知乎等各大平臺都有。

目錄

  • 一、元組和列表
    • 1.元組和列表的效能分析
    • 2.為什麼列表在 Python 中是最常用的呢?
    • 3.timeit 裡面有個 Timer 類
    • 4.timeit 裡面還有個直接用的 timeit 的方法,timeit.timeit()
    • 5.這 2 個方法有啥區別?
  • 二、命名元組
  • 三、命名元組有什麼特點?

一、元組和列表

元組vs列表

1.元組和列表的效能分析

元組和列表用來儲存資料,在元組和列表裡面查詢的時候,到底哪個更快呢?

計算建立元組和列表所需的時間:ipython 中使用timeit這個命令。

計算時間模組介紹:

import timeit
#timeit.timeit

可以用這個模組來測試函式的效能。

安裝 ipython:pip install ipython

ipython 是個互動環境,就跟我們輸入 Python 進去是一樣的。只不過它外面做了一層封裝,比 Python 互動環境更好用一點。

ipython 裡面有一個命令叫做timeit,後面可以跟一個 Python 表示式。

例如定義一個列表在後面:

敲完這行命令,返回了一行時間。這個是在記憶體中初始化一個列表,如圖可以看到建立了一千萬次,時間是 48.4ns

可以看出,建立一個元組比建立一個列表要快得多。

元組的速度比列表要快 3 倍多。在記憶體裡,當我們建立一個列表的時候,會劃分一塊區域出來,拿一塊區域給列表來儲存值。例如初始化,裡面給它留了 20 個位置在這個列表裡面儲存值。

列表佔用記憶體如圖

當儲存到一定程度,Python 直譯器檢測到列表快要盛滿了的時候,它會對列表做一個擴容。

給擴容到 200,當儲存到 150 的時候,發現又快儲存滿了,又會給你繼續擴容。

隨著資料的增多,底層會不斷給這個列表擴容。

初始化一個元組,同樣也是一千萬次,只需 12.8ns

元組是一個不可變的型別。

比如定義的元組裡面有 3 個元素,Python 直譯器在給它分記憶體的時候,就給它分了 3 個格子。

這裡面只能存 3 條資料,就這麼大,所以元組佔用的記憶體比列表要少。

元組和列表記憶體佔用對比圖

用一個列表儲存 50 條資料和用一個元組儲存 50 條資料,那麼元組佔用的記憶體要比列表小得多。

2.為什麼列表在 Python 中是最常用的呢?

因為列表比較靈活,用列表的話,可以往裡面不斷得新增元素。如果元素固定的,那就用元組。

3.timeit 裡面有個 Timer 類。

來看看這個類的原始碼:

timer=default_timer代表的是:建立一個列表、元組等,它要執行的一個次數。

看原始碼,預設是一千萬次:

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()

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)

這個模組的作用: 大家寫的功能函式,可以用它測下功能函式的速度,執行大概要多久。

預設是一千萬次,結果如下:

如果列表不加引號直接傳是會報錯的:

提示不可被呼叫!

5.這 2 個方法有啥區別?

其實它們是一個東西。

二、命名元組

元組的效能是大大優於列表的。元組、列表在使用的時候,都是通過下標索引取值的。

下標索引取值不太人性化,如果我知道資料儲存在元組裡面,但是我不知道它具體儲存的下標位置。這個時候找這個元素,還得先把下標找出來,知道下標再去拿,這樣很不方便。

字典的話,這方面就比較有優勢。資料是儲存在字典裡面的,只要通過鍵,就能把值找到。字典相對於元組和列表,有一定的優勢和劣勢。

命名元組使用的時候可以讓元組像字典一樣去取值。

例如,有個元組裡面儲存了 3 條資料:

建立一個命名元組的話,需要用到 Python 的一個內建模組from collections import namedtuple

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)

這個 tu 就是個命名元組。

student_info 是通過命名元組這個namedtuple函式建立命名元組型別:namedtuple('info_tuple',['name','age','gender'])

然後返回出來一個物件student_info

通過student_info這個物件傳入對應的元組,定義元組的時候就通過這個物件把元素寫進去,返回的就是命名元組。

三、命名元組有什麼特點?

它取值的時候可以像字典一樣取值,通過對應的鍵,找到對應的值。命名元組使用起來更像物件。

這樣用:命名元組.name

這樣就能找到 name 所對應的值:


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)

設定命名元組型別的時候,它返回的這個物件它裡面只包含了傳進去的這幾個名字。

接下來,要建立命名元組的時候,元素和它一樣多,名字和對應的元素的值是一一對應的,不能多,不能少。

否則就會報錯:

print(type(tu)) # 看下它的型別

它返回的物件和型別名用的同一個名字。

print(type(student_info))

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+原創文章,歡迎關注、交流,禁止第三方擅自轉載。

相關文章