为什么dict.get(key)的运行速度比dict [key]慢 [英] Why does dict.get(key) run slower than dict[key]

查看:152
本文介绍了为什么dict.get(key)的运行速度比dict [key]慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在运行数值积分器时,我注意到速度上存在明显差异,具体取决于我如何提取字典中字段的值

While running a numerical integrator, I noticed a noticeable difference in speed depending on how I extract the value of the field in a dictionary

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)

On my system, I notice the following difference (using 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()函数的使用?

This may seem like a small difference, but in for some arrays the difference appears to be even more dramatic. What causes this behavior, and is there some way I should alter my use of the get() function?

推荐答案

Python必须为dict.get()做更多的工作:

Python has to do more work for dict.get():

  • get是属性,因此Python必须查找它,然后将找到的描述符绑定到字典实例.
  • ()是一个调用,因此必须将当前帧压入堆栈,必须进行调用,然后必须再次从堆栈中弹出该帧才能继续.
  • get is an attribute, so Python has to look this up, and then bind the descriptor found to the dictionary instance.
  • () is a call, so the current frame has to be pushed on the stack, a call has to be made, then the frame has to be popped again from the stack to continue.

dict一起使用的[...]表示法,不需要单独的属性步骤或框架推入弹出.

The [...] notation, used with a dict, doesn't require a separate attribute step or frame push and pop.

使用 Python字节码反汇编程序dis :

You can see the difference when you use the Python bytecode disassembler 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_FUNCTIONBINARY_SUBSCR昂贵得多(带有__getitem__方法的自定义类型仍然要进行函数调用).

so the d[key] expression only has to execute a BINARY_SUBSCR opcode, while d.get(key) adds a LOAD_ATTR opcode. CALL_FUNCTION is a lot more expensive than BINARY_SUBSCR on a built-in type (custom types with __getitem__ methods still end up doing a function call).

如果字典中存在键的多数,则可以使用try...except KeyError处理丢失的键:

If the majority of your keys exist in the dictionary, you could use try...except KeyError to handle missing keys:

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

如果没有异常,则异常处理很便宜.

Exception handling is cheap if there are no exceptions.

这篇关于为什么dict.get(key)的运行速度比dict [key]慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆