为什么dict.get(key)的运行速度比dict [key]慢 [英] Why does dict.get(key) run slower than 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_FUNCTION
比BINARY_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屋!