在日常使用 python 時,我們經常需要建立乙個列表,相信大家都很熟練了吧?
# 方法一:使用成對的方括號語法
list_a =
# 方法二:使用內建的 list()
list_b = list()
上面的兩種寫法,你經常使用哪乙個呢?是否思考過它們的區別呢?
對於第乙個問題,使用timeit
模組的 timeit() 函式就能簡單地測算出來:
如上圖所示,在各自呼叫一千萬次的情況下, 建立方式只花費了 0.47 秒,而 list() 建立方式要花費 1.75 秒,所以,後者的耗時是前者的 3.7 倍!
這就回答了剛才的問題:建立空列表時, 要比 list() 快不少。
注:timeit() 函式的效率跟執行環境相關,每次執行結果會有微小差異。我在 python3.8 版本實驗了幾次,總體上 速度是 list() 的 3 倍多一點。那麼,我們繼續來分析一下第二個問題:為什麼 會更快呢?
這一次我們可以使用dis
模組的 dis() 函式,看看兩者執行的位元組碼有何差別:
如上圖所示, 的位元組碼有兩條指令(build_list 與 return_value),而 list() 的位元組碼有三條指令(load_name、call_function 與 return_value)。
這些指令意味著什麼呢?該如何理解呢?
首先,對於 ,它是 python 中的一組字面量(literal),像數字之類的字面量一樣,表示確切的固定值。
也就是說,python 在解析到它時,就知道它要表示乙個列表,因此會直接呼叫直譯器中構建列表的方法(對應build_list),來建立列表,所以是一步到位。
而對於 list(),「list」只是乙個普通的名稱,並不是字面量,也就是說直譯器一開始並不認識它。
因此,直譯器的第一步是要找到這個名稱(對應load_name)。它會按照一定的順序,在各個作用域中逐一查詢(區域性作用域--全域性作用域--內建作用域),直到找到為止,找不到則丟擲nameerror
。
直譯器看到「list」之後是一對圓括號,因此第二步是把這個名稱當作可呼叫物件來呼叫,即把它當成乙個函式進行呼叫(對應 call_function)。
因此,list() 在建立列表時,需要經過名稱查詢與函式呼叫兩個步驟,才能真正開始建立列表(注:call_function 在底層還會有一些函式呼叫過程,才能走到跟 build_list 相通的邏輯,此處我們忽略不計)。
看完前兩個問題的解答過程,你也許覺得還不夠過癮,而且可能覺得就算知道了這個冷知識,也不會有多大的幫助,似乎那微弱的提公升顯得微不足道。
而且,由於有發散性思考的習慣,我還想到了另外乙個挺有意思的問題:list() 的速度能否提公升呢?
我不久前正好討論到這個問題,也就是在剛剛發布的 python 3.9.0 版本中,它給 list() 實現了更快的 vectorcall 協議,因此執行速度會有一定的提公升。
根據我多輪的測試結果,在新版本中執行 list() 一千萬次,耗時大概在 1 秒左右,也就是 執行耗時的 2 倍,相比於前面接近 4 倍的資料,當前版本總體上是提公升了不少。
在這裡還是要推薦下我自己建的python學習群:609616831,群裡都是學python的,如果你想學或者正在學習python ,歡迎你加入,大家都是軟體開發黨,不定期分享乾貨(只有python軟體開發相關的),包括我自己整理的乙份2020最新的python高階資料和零基礎教學,歡迎高階中和對python感興趣的小夥伴加入!
為什麼 比list()更快?
我最近比較了和list 的處理速度,並且驚訝地發現執行速度比list 快三倍以上。我跑了相同的測試與 和dict 結果幾乎相同 和 兩個花了大約0.128sec 百萬次,而list 和dict 大約花費每個0.428sec 萬次。後來我查了查原因,得到的結論如下 list 需要全域性查詢和函式呼叫,...
Spark 為什麼比Hadoop快
spark sql比hadoop hive快,是有一定條件的,而且不是spark sql的引擎比hive的引擎快,相反,hive的hql引擎還比spark sql的引擎更快。color red b 其實,關鍵還是在於spark 本身快。b color color red size large b s...
Spark 為什麼比Hadoop快
spark sql比hadoop hive快,是有一定條件的,而且不是spark sql的引擎比hive的引擎快,相反,hive的hql引擎還比spark sql的引擎更快。color red b 其實,關鍵還是在於spark 本身快。b color color red size large b s...