簡體   English   中英

為什么dict.get(key)比dict [key]運行得慢

[英]Why does dict.get(key) run slower than dict[key]

在運行數值積分器時,我注意到速度的明顯差異取決於我如何在字典中提取字段的值

import numpy as np

def bad_get(mydict):
    '''Extract the name field using get()'''
    output = mydict.get('name', None)
    return output

def good_get(mydict):
    '''Extract the name field using if-else'''
    if 'name' in mydict:
        output = mydict['name']
    else:
        output = None
    return output


name_dict = dict()
name_dict['name'] = np.zeros((5000,5000))

在我的系統上,我注意到以下區別(使用iPython)

%%timeit
bad_get(name_dict) 

The slowest run took 7.75 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 247 ns per loop

相比

%%timeit
good_get(name_dict)  

1000000 loops, best of 3: 188 ns per loop

這似乎是一個小差異,但對於某些陣列而言,差異似乎更為顯着。 導致這種行為的原因是什么,有什么方法可以改變我對get()函數的使用?

Python必須為dict.get()做更多的工作:

  • get是一個屬性,因此Python必須查找它,然后將找到的描述符綁定到字典實例。
  • ()是一個調用,因此必須將當前幀推入堆棧,必須進行調用,然后必須再次從堆棧中彈出幀以繼續。

[...]符號與dict一起使用,不需要單獨的屬性步驟或幀推送和彈出。

你可以看到差異,當你使用Python的字節碼反匯編dis

>>> import dis
>>> dis.dis(compile('d[key]', '', 'eval'))
  1           0 LOAD_NAME                0 (d)
              3 LOAD_NAME                1 (key)
              6 BINARY_SUBSCR
              7 RETURN_VALUE
>>> dis.dis(compile('d.get(key)', '', 'eval'))
  1           0 LOAD_NAME                0 (d)
              3 LOAD_ATTR                1 (get)
              6 LOAD_NAME                2 (key)
              9 CALL_FUNCTION            1
             12 RETURN_VALUE

所以d[key]表達式只需要執行BINARY_SUBSCR操作碼,而d.get(key)添加一個LOAD_ATTR操作碼。 CALL_FUNCTION比內置類型的BINARY_SUBSCR貴很多(帶有__getitem__方法的自定義類型最終仍會進行函數調用)。

如果你的大多數密鑰存在於字典中,你可以使用try...except KeyError來處理丟失的密鑰:

try:
    return mydict['name']
except KeyError:
    return None

如果沒有例外,異常處理很便宜。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM