减少函数调用

1 投票
4 回答
1217 浏览
提问于 2025-04-15 22:15

我对我的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

其中 setOfPeople 是一个包含 person 对象的列表。我尝试了以下方法:

    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))

return self.utility[theCar]

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

有没有什么想法可以进一步加速这个过程?我用了Alex建议的方法,把时间缩短了一半。还能再快点吗?谢谢。

4 个回答

1

方法其实就是和一个对象绑定在一起的函数:

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

不过,这并不意味着调用函数的过程被省略了,它只是省去了查找属性的步骤。

1

可以试试这个方法(假设所有的人都是同一种类型 Person):

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

另外,使用 is None 来判断是否为“没有值”会比 == None 稍微快一点。你可以试试换一下 and 的顺序,看是否有帮助。

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 的调用次数)。你的性能分析结果显示这个函数(扣除它对其他函数的调用)花了多少时间,相比于这个方法(还有可能的属性)呢?

撰写回答