Python高效包装器

时间:2013-03-06 22:45:16

标签: python-2.7 overhead

Python函数调用相对expensive.但是我一直在遇到我希望能够以不同方式调用函数的情况,最简单的方法似乎是在函数周围创建一个光包装器。不同的电话。

是否有更多的pythonic和/或更有效的方式来启用更多方式来调用函数?


对于一个完全做作的,过于简单的例子来说明我的要求:

from math import sqrt
from collections import namedtuple

Point = namedtuple('Point', 'x y')

def distFunc(x1, y1, x2, y2):
    return sqrt((x1-x2)**2 + (y1-y2)**2)

def pointDistFunc(p1, p2):
    return distFunc(p1.x, p1.y, p2.x, p2.y)

有没有更好的方法来编写pointDistFunc?

实际上,这个时间:

p1 = Point(1, 1)
p2 = Point(100, 100)

if __name__ == '__main__':
    import timeit
    print(timeit.timeit("distFunc(1, 1, 100, 100)", setup="from __main__ import distFunc"))
    print(timeit.timeit('pointDistFunc(p1, p2)', setup= 'from __main__ import pointDistFunc, p1, p2'))

给出:

0.392938508373
0.977704155415

所以开销似乎很明显。

1 个答案:

答案 0 :(得分:2)

我认为一般来说,最好的方法是编写最清晰的代码,而不是担心效率问题。我认为在这种情况下,我会按照您已经做过的方式对其进行编码,而不用担心它。

但是如果你知道一些代码将被大量调用,并且你希望它尽可能快,那么你可以通过重写来加快速度。在你琐碎的例子中,你可以通过重写包装器来获得速度来进行计算:

def pointDistFunc(p1, p2):
    return sqrt((p1.x-p2.x)**2 + (p1.y-p2.y)**2)

理想情况下,您应该在某处检查

进行一些单元测试
pointDistFunc(p1, p2) == distFunc(p1.x, p1.y, p2.x, p2.y)

这样,如果您最终更改distFunc()但又忘记更改pointDistFunc(),则测试将失败,系统会提醒您。

你提到的那条准则并不是为了阻止你写封皮;更多的是建议如何重写涉及列表之类的热点:

def gen_point_dist_from_lst(lst, p2):
    return (sqrt((p1.x-p2.x)**2 + (p1.y-p2.y)**2) for p1 in lst)

如果列表有1000个点,那么与直接的生成器表达式

相比,上面保存了2000个函数调用
(pointDistFunc(p1, p2) for p1 in lst)

关键是在尝试这些技巧之前先遇到问题。如果你的程序运行速度已经足够快,也许你不需要优化任何东西。如果需要更快的代码,你可以尝试这些技巧。

P.S。如果你可以使用PyPy来做你正在做的事情,它应该消除函数调用的开销。 PyPy有一个即时编译器,可以为您优化程序中的热点。

http://speed.pypy.org/