减少函数调用

时间:2010-05-01 23:12:37

标签: python performance

我描述了我的python程序,发现以下函数运行时间太长。也许,我可以使用不同的算法,让它运行得更快。但是,我已经读过,我也可以通过减少函数调用来提高速度,特别是在循环中重复调用时。我是一个python新手,想学习如何做到这一点,看看它能获得多快。目前,功能是:

def potentialActualBuyers(setOfPeople,theCar,price):
    count=0
 for person in setOfPeople:
  if person.getUtility(theCar) >= price and person.periodCarPurchased==None:
   count += 1
 return count

其中setOfPeopleperson个对象的列表。我尝试了以下方法:

    def potentialActualBuyers(setOfPeople,theCar,price):
        count=0
        Utility=person.getUtility
        for person in setOfPeople:
           if Utility(theCar) >= price and person.periodCarPurchased==None:
               count += 1
        return count

然而,这给了我一个错误local variable 'person' referenced before assignment 任何建议,如何减少函数调用或任何其他可以使代码更快的更改。

同样,我是一个python新手,尽管我可能能够使用更好的算法,但仍然值得学习上述问题的答案。

非常感谢。

*****编辑*****

添加getUtility方法:

 def getUtility(self,theCar):
  if theCar in self.utility.keys():
   return self.utility[theCar]
  else:
   self.utility[theCar]=self.A*(math.pow(theCar.mpg,self.alpha))*(math.pow(theCar.hp,self.beta))*(math.pow(theCar.pc,self.gamma))

返回self.utility [theCar]

*****编辑:要求新想法*****

任何想法如何进一步提高速度。我用Alex建议的方法把时间缩短了一半。我可以进一步加快速度吗? 感谢。

4 个答案:

答案 0 :(得分:2)

我怀疑你在这种情况下可以通过提升person.getUtility的查找来获得更多的加速(按类,而不是实例,正如其他实例所指出的那样)。也许......

return sum(1 for p in setOfPeople
           if p.periodCarPurchased is None
           and p.getUtility(theCar) >= price)

但我怀疑大部分时间实际上是花在getUtility的执行上(并且可能在p.periodCarPurchased的查找中,如果这是一些奇特的属性而不是普通的旧属性 - 我搬了在and之前的后者,以防它一个普通属性并且可以保存一些getUtility次调用)。你的分析是什么说这个函数花费的时间(扣除对其他人的调用)与所讨论的方法(可能是属性)相比?

答案 1 :(得分:1)

尝试改为(假设所有人都属于同一类型Person):

Utility = Person.getUtility
for person in setOfPeople:
    if Utility (person, theCar) >= ...

此外,使用== None代替is None的速度要快一些。如果交换and条款有帮助,请尝试使用。

答案 2 :(得分:1)

方法只是绑定到对象的函数:

    Utility = Person.getUtility
    for person in setOfPeople:
       if Utility(person, theCar) ...

但这并没有消除函数调用,它消除了属性查找。

答案 3 :(得分:1)

这一行使我的眼睛流血:

   self.utility[theCar]=self.A*(math.pow(theCar.mpg,self.alpha))*(math.pow(theCar.hp,self.beta))*(math.pow(theCar.pc,self.gamma))

让它变得清晰易读,然后看看它是否更快。首先是一些空格:

self.utility[theCar] = self.A * (math.pow(theCar.mpg, self.alpha)) * (math.pow(theCar.hp, self.beta)) * (math.pow(theCar.pc, self.gamma))

现在我们可以看到有很多冗余的括号;删除它们:

self.utility[theCar] = self.A * math.pow(theCar.mpg, self.alpha) * math.pow(theCar.hp, self.beta) * math.pow(theCar.pc, self.gamma)

嗯:math.pow和3次函数调用的3次查找。您有三种权力选择:x ** y,内置pow(x, y[, z])math.pow(x, y)。除非你有充分的理由使用其中一个,否则最好(恕我直言)选择x ** y;保存属性查找和函数调用。

self.utility[theCar] = self.A * theCar.mpg ** self.alpha * theCar.hp ** self.beta * theCar.pc ** self.gamma

当我们在这里时,让我们摆脱水平滚动条:

self.utility[theCar] = (self.A
    * theCar.mpg ** self.alpha
    * theCar.hp  ** self.beta
    * theCar.pc  ** self.gamma)

可能需要对现有代码进行相当重写,并且无论如何(在Python中)可能无法帮助,通过在任何地方记录日志并使用log_utility = log_A + log_mpg * alpha ...

来避免大部分功耗计算