为什么内联 if/else 比 Python 中的 .get() 快? [英] Why is an inline if/else faster than a .get() in Python?

查看:40
本文介绍了为什么内联 if/else 比 Python 中的 .get() 快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前审查了一些代码,开发人员编写了一个内联 if/else 而不是 get() 来从中检索元素一个列表,如果它存在(否则给它一个默认值).我决定在 repl 上添加一些 timeit 代码,但对结果感到非常困惑.if/else 占用 get() 时间的 1/3.

这里是repl代码,下面是repl中的代码以及后人的结果:

导入时间D = {"a": 1, "b": 2, "c": 3}def ef(): 如果 D 中有 'a' 则返回 D['a'] else 1def gt(): 返回 D.get('a', 1)打印 "gt1", timeit.timeit(gt, number=10000)打印 "ef1", timeit.timeit(ef, number=10000)打印 "ef2", timeit.timeit(ef, number=10000)打印 "gt2", timeit.timeit(gt, number=10000)

和结果:

gt1 0.0659999847412ef1 0.0239999294281ef2 0.0249998569489GT2 0.0539999008179

以及上述 timeit 调用的 10 次迭代的视觉效果,其中结果已乘以 10000 以进行表示

解决方案

D.get() 路径包括一个属性查找和一个方法调用:

<预><代码>>>>导入文件>>>D = {"a": 1, "b": 2, "c": 3}>>>def gt(): 返回 D.get('a', 1)...>>>dis.dis(gt)1 0 LOAD_GLOBAL 0 (D)3 LOAD_ATTR 1(获得)6 LOAD_CONST 1 ('a')9 LOAD_CONST 2 (1)12 CALL_FUNCTION 215 RETURN_VALUE

属性查找 (LOAD_ATTR) 特别会减慢速度.

如果您删除属性查找(并为 in 测试提供一个本地使用),则该字段将被拉平:

<预><代码>>>>def gt_fast(D_get=D.get): return D_get('a', 1)...>>>def ef_fast(D=D): 返回 D['a'] 如果 D 中的 'a' else 1...>>>timeit.timeit(gt_fast)0.2174091339111328>>>timeit.timeit(ef_fast)0.2139298915863037

I was reviewing some code earlier and the developer wrote an inline if/else rather than a get() to retrieve an element from a list if it exists (otherwise give it a default value). I decided to spring some timeit code on repl and was pretty confused by the result. The if/else takes 1/3 the time of the get().

Here is the repl code, and below is the code in the repl as well as the result for posterity:

import timeit

D = {"a": 1, "b": 2, "c": 3}

def ef(): return D['a'] if 'a' in D else 1

def gt(): return D.get('a', 1)

print "gt1", timeit.timeit(gt, number=10000)
print "ef1", timeit.timeit(ef, number=10000)
print "ef2", timeit.timeit(ef, number=10000)
print "gt2", timeit.timeit(gt, number=10000)

and the results:

gt1 0.0659999847412
ef1 0.0239999294281
ef2 0.0249998569489
gt2 0.0539999008179

and a visual of 10 iterations of the above timeit calls, where the result has been multiplied by 10000 for representation purposes

解决方案

The D.get() path includes an attribute lookup, and a method call:

>>> import dis
>>> D = {"a": 1, "b": 2, "c": 3}
>>> def gt(): return D.get('a', 1)
... 
>>> dis.dis(gt)
  1           0 LOAD_GLOBAL              0 (D)
              3 LOAD_ATTR                1 (get)
              6 LOAD_CONST               1 ('a')
              9 LOAD_CONST               2 (1)
             12 CALL_FUNCTION            2
             15 RETURN_VALUE        

The attribute lookup (LOAD_ATTR) especially slows things down.

If you remove the attribute lookup (and give the in test a local to work with), the field is evened out:

>>> def gt_fast(D_get=D.get): return D_get('a', 1)
... 
>>> def ef_fast(D=D): return D['a'] if 'a' in D else 1
... 
>>> timeit.timeit(gt_fast)
0.2174091339111328
>>> timeit.timeit(ef_fast)
0.2139298915863037

这篇关于为什么内联 if/else 比 Python 中的 .get() 快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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