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
所以开销似乎很明显。
答案 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有一个即时编译器,可以为您优化程序中的热点。