2013-03-06 19 views
1

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

是否有更多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?

正因为如此,这timeit:

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 

所以开销似乎是明显的。

+0

如果你只想*添加*参数,你可以用'functools.partial()',它采用C避免压栈流行。 – 2013-03-06 22:46:38

回答

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/

+0

谢谢。只是忽视效率可能最终成为最好的方法。在一个简单的例子中,重写很容易,但是在更复杂的情况下变得不太实际,特别是当代码稍后有可能改变时。 – TimothyAWiseman 2013-03-07 17:00:47

相关问题