2012-06-22 18 views
19

在此page,我看到一些有趣的事情:在字典中使用字符串作爲鍵總是更快嗎?

請注意,沒有對類型的字典是(實踐)只處理海峽鍵快速路徑;這不會影響算法的複雜性,但它可以顯着影響常數因素:典型程序完成的速度。

那究竟是什麼意思?

這是否意味着使用字符串作爲關鍵總是更快?

如果是,爲什麼?

更新:

感謝有關優化建議!但我實際上對簡單的事實更感興趣,而不是是否或何時應該優化。

更新2:

感謝偉大的答案,我會舉從@DaveWebb這裏提供的link內容:

「 ...

ma_lookup最初設置爲lookdict_string函數(在3.0中更名爲lookdict_unicode),其作爲因爲詞典中的鍵和被搜索的鍵都是標準的PyStringObject。然後,它可以進行一些優化,例如減輕各種錯誤檢查,因爲字符串到字符串的比較決不會引發異常。也不需要進行豐富的對象比較,這意味着我們避免直接調用PyObject_RichCompareBool,並始終使用_PyString_Eq

... 「

此外,對於實驗的數字,我想如果沒有INT-到字符串的轉換

+2

我想這一切都歸結爲關鍵對象的__hash__方法有多快。我猜想,對一個字符串進行散列相當簡單,但我會對字典查找花費在散列中的比例非常感興趣。 – Wilduck

+0

您的更新不會改變任何內容。不,在大多數情況下,除非你的鑰匙是絃樂器,否則它不會更快。 –

+0

@Lattyware鏈接頁面似乎意味着每個查詢*的速度提高*不僅僅是用於構建。 – Wilduck

回答

17

基於Python字典的C代碼已針對String鍵進行了優化。 You can read about this here(以及博客引用的書中)。

如果Python運行時知道你的字典只包含字符串鍵,它可以做一些事情,比如不能處理字符串比較和忽略豐富比較運算符時不會發生的錯誤。這會使得字符串鍵只有dict的常見情況稍微快一點。 (更新:時間顯示它不止一點。)

但是,這不太可能會對大多數Python程序的運行時間產生重大變化。如果您已經測量並發現dict查找成爲代碼中的瓶頸,那麼只需要擔心此優化。 As the famous quote says, "Premature optimization is the root of all evil."

只有這樣,才能看到多少更快的東西真的是,是次地:

>>> timeit.timeit('a["500"]','a ={}\nfor i in range(1000): a[str(i)] = i') 
0.06659698486328125 
>>> timeit.timeit('a[500]','a ={}\nfor i in range(1000): a[i] = i') 
0.09005999565124512 

因此,使用字符串鍵約30%的速度甚至比int鑰匙,我不得不承認我對差異的大小感到驚訝。

+0

您的測試假設獲得''500''而不是'500''沒有任何成本 - 這會產生巨大的差異 - 請參閱我的答案。 –

+1

問題問串鍵是否總是比較快,我的測試是用來顯示它的功能。我不認爲這個問題是關於從另一個對象轉換爲字符串並將其用作關鍵字的問題 - 這會因多種原因而變得糟糕 - 而只是在選擇可用時總是值得使用字符串。 –

+0

這是脫離了上下文。如果知道使用字符串鍵的速度會更快,那麼使用字符串鍵會使速度變慢的方式是沒有用的。 –

8

由於這隻影響差異的大小將是更大不變的時候,它可能根本沒有關係,你真的需要優化的唯一時候是當你使用非常大的數據集時 - 這沒有什麼影響

這是什麼意思是在這種情況下在那裏你有以字符串作爲鍵的小字典,Python會很快 - 這是一個常見的用法,所以它已被優化。如Ignacio Vazquez-Abrams指出的那樣,將密鑰轉換爲字符串可能會花費(遠遠)超過從dict字符串獲得的輕微提升。

簡而言之就是與您的情況相關的事情 - 只有在有需要時才能進行優化,而不是在之前進行優化。

一些測試:

python -m timeit -s "a={key: 1 for key in range(1000)}" "a[500]" 
10000000 loops, best of 3: 0.0773 usec per loop 

python -m timeit -s "a={str(key): 1 for key in range(1000)}" "a[\"500\"]" 
10000000 loops, best of 3: 0.0452 usec per loop 

python -m timeit -s "a={str(key): 1 for key in range(1000)}" "a[str(500)]" 
1000000 loops, best of 3: 0.244 usec per loop 

正如你所看到的,而基於字符串的字典比較快,轉換關鍵是非常昂貴的比較,完全緩解增益(然後一些)。

所以,是的,如果你正在使用的數據是僅被用作鍵的字典,什麼格式的商店他們也無所謂,然後字符串是較好的,一個小字典。實際上,這是非常罕見的情況(你可能已經在使用字符串)。

+4

特別是因爲將某些類型轉換爲字符串可能比僅僅將它們用作關鍵字更昂貴。 –

+0

對不起,我想我應該修改我的問題 – xvatar

+0

@ IgnacioVazquez-Abrams非常真實。 –

相關問題