Python [] 竟然比 list() 快3倍?。。?/h1>
點(diǎn)擊上方“小白學(xué)視覺(jué)”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)


作者 | 豌豆花下貓
來(lái)源 | Python貓
在日常使用 Python 時(shí),我們經(jīng)常需要?jiǎng)?chuàng)建一個(gè)列表,相信大家都很熟練了吧?
# 方法一:使用成對(duì)的方括號(hào)語(yǔ)法
list_a = []
# 方法二:使用內(nèi)置的 list()
list_b = list()
上面的兩種寫(xiě)法,你經(jīng)常使用哪一個(gè)呢?是否思考過(guò)它們的區(qū)別呢?
讓我們開(kāi)門(mén)見(jiàn)山,直接拋出本文的問(wèn)題吧:兩種創(chuàng)建列表的 [] 與 list() 寫(xiě)法,哪一個(gè)更快呢,為什么它會(huì)更快呢?
1、 [] 是 list() 的三倍快
對(duì)于第一個(gè)問(wèn)題,使用timeit模塊的 timeit() 函數(shù)就能簡(jiǎn)單地測(cè)算出來(lái):
>>> import timeit
>>> timeit.timeit('[]', number=10**7)
>>> timeit.timeit('list()', number=10**7)

如上圖所示,在各自調(diào)用一千萬(wàn)次的情況下,[] 創(chuàng)建方式只花費(fèi)了 0.47 秒,而 list() 創(chuàng)建方式要花費(fèi) 1.75 秒,所以,后者的耗時(shí)是前者的 3.7 倍!
這就回答了剛才的問(wèn)題:創(chuàng)建空列表時(shí),[] 要比 list() 快不少。
注:timeit() 函數(shù)的效率跟運(yùn)行環(huán)境相關(guān),每次執(zhí)行結(jié)果會(huì)有微小差異。我在 Python3.8 版本實(shí)驗(yàn)了幾次,總體上 [] 速度是 list() 的 3 倍多一點(diǎn)。
2、list() 比 [] 執(zhí)行步驟多
那么,我們繼續(xù)來(lái)分析一下第二個(gè)問(wèn)題:為什么 [] 會(huì)更快呢?
這一次我們可以使用dis模塊的 dis() 函數(shù),看看兩者執(zhí)行的字節(jié)碼有何差別:
>>> from dis import dis
>>> dis("[]")
>>> dis("list()")

如上圖所示,[] 的字節(jié)碼有兩條指令(BUILD_LIST 與 RETURN_VALUE),而 list() 的字節(jié)碼有三條指令(LOAD_NAME、CALL_FUNCTION 與 RETURN_VALUE)。
這些指令意味著什么呢?該如何理解呢?
首先,對(duì)于 [],它是 Python 中的一組字面量(literal),像數(shù)字之類的字面量一樣,表示確切的固定值。
也就是說(shuō),Python 在解析到它時(shí),就知道它要表示一個(gè)列表,因此會(huì)直接調(diào)用解釋器中構(gòu)建列表的方法(對(duì)應(yīng)BUILD_LIST),來(lái)創(chuàng)建列表,所以是一步到位。
而對(duì)于 list(),“l(fā)ist”只是一個(gè)普通的名稱,并不是字面量,也就是說(shuō)解釋器一開(kāi)始并不認(rèn)識(shí)它。
因此,解釋器的第一步是要找到這個(gè)名稱(對(duì)應(yīng)LOAD_NAME)。它會(huì)按照一定的順序,在各個(gè)作用域中逐一查找(局部作用域--全局作用域--內(nèi)置作用域),直到找到為止,找不到則拋出NameError。
解釋器看到“l(fā)ist”之后是一對(duì)圓括號(hào),因此第二步是把這個(gè)名稱當(dāng)作可調(diào)用對(duì)象來(lái)調(diào)用,即把它當(dāng)成一個(gè)函數(shù)進(jìn)行調(diào)用(對(duì)應(yīng) CALL_FUNCTION)。
因此,list() 在創(chuàng)建列表時(shí),需要經(jīng)過(guò)名稱查找與函數(shù)調(diào)用兩個(gè)步驟,才能真正開(kāi)始創(chuàng)建列表(注:CALL_FUNCTION 在底層還會(huì)有一些函數(shù)調(diào)用過(guò)程,才能走到跟 BUILD_LIST 相通的邏輯,此處我們忽略不計(jì))。
至此,我們就可以回答前面的問(wèn)題了:因?yàn)?list() 涉及的執(zhí)行步驟更多,因此它比 [] 要慢一些。
3、list() 的速度提升
看完前兩個(gè)問(wèn)題的解答過(guò)程,你也許覺(jué)得還不夠過(guò)癮,而且可能覺(jué)得就算知道了這個(gè)冷知識(shí),也不會(huì)有多大的幫助,似乎那微弱的提升顯得微不足道。
而且,由于有發(fā)散性思考的習(xí)慣,我還想到了另外一個(gè)挺有意思的問(wèn)題:list() 的速度能否提升呢?
我不久前寫(xiě)過(guò)一篇文章正好討論到這個(gè)問(wèn)題,也就是在剛剛發(fā)布的 Python 3.9.0 版本中,它給 list() 實(shí)現(xiàn)了更快的 vectorcall 協(xié)議,因此執(zhí)行速度會(huì)有一定的提升。

感興趣的同學(xué)可以去 Python 官網(wǎng)下載 3.9 版本。
根據(jù)我多輪的測(cè)試結(jié)果,在新版本中運(yùn)行 list() 一千萬(wàn)次,耗時(shí)大概在 1 秒左右,也就是 [] 運(yùn)行耗時(shí)的 2 倍,相比于前面接近 4 倍的數(shù)據(jù),當(dāng)前版本總體上是提升了不少。
至此,我們已回答完一連串的疑問(wèn),如果你覺(jué)得有收獲,請(qǐng)點(diǎn)贊支持!歡迎大家關(guān)注后續(xù)更多精彩內(nèi)容。
好消息!
小白學(xué)視覺(jué)知識(shí)星球
開(kāi)始面向外開(kāi)放啦??????

下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程
在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):擴(kuò)展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺(jué)、目標(biāo)跟蹤、生物視覺(jué)、超分辨率處理等二十多章內(nèi)容。
下載2:Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目52講 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目,即可下載包括圖像分割、口罩檢測(cè)、車(chē)道線檢測(cè)、車(chē)輛計(jì)數(shù)、添加眼線、車(chē)牌識(shí)別、字符識(shí)別、情緒檢測(cè)、文本內(nèi)容提取、面部識(shí)別等31個(gè)視覺(jué)實(shí)戰(zhàn)項(xiàng)目,助力快速學(xué)校計(jì)算機(jī)視覺(jué)。
下載3:OpenCV實(shí)戰(zhàn)項(xiàng)目20講 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):OpenCV實(shí)戰(zhàn)項(xiàng)目20講,即可下載含有20個(gè)基于OpenCV實(shí)現(xiàn)20個(gè)實(shí)戰(zhàn)項(xiàng)目,實(shí)現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。
交流群
歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺(jué)、傳感器、自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN、算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺(jué)SLAM“。請(qǐng)按照格式備注,否則不予通過(guò)。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~
瀏覽
22
點(diǎn)擊上方“小白學(xué)視覺(jué)”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)

來(lái)源 | Python貓
在日常使用 Python 時(shí),我們經(jīng)常需要?jiǎng)?chuàng)建一個(gè)列表,相信大家都很熟練了吧?
# 方法一:使用成對(duì)的方括號(hào)語(yǔ)法
list_a = []
# 方法二:使用內(nèi)置的 list()
list_b = list()
上面的兩種寫(xiě)法,你經(jīng)常使用哪一個(gè)呢?是否思考過(guò)它們的區(qū)別呢?
讓我們開(kāi)門(mén)見(jiàn)山,直接拋出本文的問(wèn)題吧:兩種創(chuàng)建列表的 [] 與 list() 寫(xiě)法,哪一個(gè)更快呢,為什么它會(huì)更快呢?
1、 [] 是 list() 的三倍快
對(duì)于第一個(gè)問(wèn)題,使用timeit模塊的 timeit() 函數(shù)就能簡(jiǎn)單地測(cè)算出來(lái):
>>> import timeit
>>> timeit.timeit('[]', number=10**7)
>>> timeit.timeit('list()', number=10**7)

如上圖所示,在各自調(diào)用一千萬(wàn)次的情況下,[] 創(chuàng)建方式只花費(fèi)了 0.47 秒,而 list() 創(chuàng)建方式要花費(fèi) 1.75 秒,所以,后者的耗時(shí)是前者的 3.7 倍!
這就回答了剛才的問(wèn)題:創(chuàng)建空列表時(shí),[] 要比 list() 快不少。
注:timeit() 函數(shù)的效率跟運(yùn)行環(huán)境相關(guān),每次執(zhí)行結(jié)果會(huì)有微小差異。我在 Python3.8 版本實(shí)驗(yàn)了幾次,總體上 [] 速度是 list() 的 3 倍多一點(diǎn)。
2、list() 比 [] 執(zhí)行步驟多
那么,我們繼續(xù)來(lái)分析一下第二個(gè)問(wèn)題:為什么 [] 會(huì)更快呢?
這一次我們可以使用dis模塊的 dis() 函數(shù),看看兩者執(zhí)行的字節(jié)碼有何差別:
>>> from dis import dis
>>> dis("[]")
>>> dis("list()")

如上圖所示,[] 的字節(jié)碼有兩條指令(BUILD_LIST 與 RETURN_VALUE),而 list() 的字節(jié)碼有三條指令(LOAD_NAME、CALL_FUNCTION 與 RETURN_VALUE)。
這些指令意味著什么呢?該如何理解呢?
首先,對(duì)于 [],它是 Python 中的一組字面量(literal),像數(shù)字之類的字面量一樣,表示確切的固定值。
也就是說(shuō),Python 在解析到它時(shí),就知道它要表示一個(gè)列表,因此會(huì)直接調(diào)用解釋器中構(gòu)建列表的方法(對(duì)應(yīng)BUILD_LIST),來(lái)創(chuàng)建列表,所以是一步到位。
而對(duì)于 list(),“l(fā)ist”只是一個(gè)普通的名稱,并不是字面量,也就是說(shuō)解釋器一開(kāi)始并不認(rèn)識(shí)它。
因此,解釋器的第一步是要找到這個(gè)名稱(對(duì)應(yīng)LOAD_NAME)。它會(huì)按照一定的順序,在各個(gè)作用域中逐一查找(局部作用域--全局作用域--內(nèi)置作用域),直到找到為止,找不到則拋出NameError。
解釋器看到“l(fā)ist”之后是一對(duì)圓括號(hào),因此第二步是把這個(gè)名稱當(dāng)作可調(diào)用對(duì)象來(lái)調(diào)用,即把它當(dāng)成一個(gè)函數(shù)進(jìn)行調(diào)用(對(duì)應(yīng) CALL_FUNCTION)。
因此,list() 在創(chuàng)建列表時(shí),需要經(jīng)過(guò)名稱查找與函數(shù)調(diào)用兩個(gè)步驟,才能真正開(kāi)始創(chuàng)建列表(注:CALL_FUNCTION 在底層還會(huì)有一些函數(shù)調(diào)用過(guò)程,才能走到跟 BUILD_LIST 相通的邏輯,此處我們忽略不計(jì))。
至此,我們就可以回答前面的問(wèn)題了:因?yàn)?list() 涉及的執(zhí)行步驟更多,因此它比 [] 要慢一些。
3、list() 的速度提升
看完前兩個(gè)問(wèn)題的解答過(guò)程,你也許覺(jué)得還不夠過(guò)癮,而且可能覺(jué)得就算知道了這個(gè)冷知識(shí),也不會(huì)有多大的幫助,似乎那微弱的提升顯得微不足道。
而且,由于有發(fā)散性思考的習(xí)慣,我還想到了另外一個(gè)挺有意思的問(wèn)題:list() 的速度能否提升呢?
我不久前寫(xiě)過(guò)一篇文章正好討論到這個(gè)問(wèn)題,也就是在剛剛發(fā)布的 Python 3.9.0 版本中,它給 list() 實(shí)現(xiàn)了更快的 vectorcall 協(xié)議,因此執(zhí)行速度會(huì)有一定的提升。

感興趣的同學(xué)可以去 Python 官網(wǎng)下載 3.9 版本。
根據(jù)我多輪的測(cè)試結(jié)果,在新版本中運(yùn)行 list() 一千萬(wàn)次,耗時(shí)大概在 1 秒左右,也就是 [] 運(yùn)行耗時(shí)的 2 倍,相比于前面接近 4 倍的數(shù)據(jù),當(dāng)前版本總體上是提升了不少。
至此,我們已回答完一連串的疑問(wèn),如果你覺(jué)得有收獲,請(qǐng)點(diǎn)贊支持!歡迎大家關(guān)注后續(xù)更多精彩內(nèi)容。
好消息!
小白學(xué)視覺(jué)知識(shí)星球
開(kāi)始面向外開(kāi)放啦??????
下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):擴(kuò)展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺(jué)、目標(biāo)跟蹤、生物視覺(jué)、超分辨率處理等二十多章內(nèi)容。 下載2:Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目52講 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目,即可下載包括圖像分割、口罩檢測(cè)、車(chē)道線檢測(cè)、車(chē)輛計(jì)數(shù)、添加眼線、車(chē)牌識(shí)別、字符識(shí)別、情緒檢測(cè)、文本內(nèi)容提取、面部識(shí)別等31個(gè)視覺(jué)實(shí)戰(zhàn)項(xiàng)目,助力快速學(xué)校計(jì)算機(jī)視覺(jué)。 下載3:OpenCV實(shí)戰(zhàn)項(xiàng)目20講 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):OpenCV實(shí)戰(zhàn)項(xiàng)目20講,即可下載含有20個(gè)基于OpenCV實(shí)現(xiàn)20個(gè)實(shí)戰(zhàn)項(xiàng)目,實(shí)現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。 交流群
歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺(jué)、傳感器、自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN、算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺(jué)SLAM“。請(qǐng)按照格式備注,否則不予通過(guò)。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~
