Сокращение вызовов функций - PullRequest
1 голос
/ 02 мая 2010

Я профилировал свою программу на 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]

***** РЕДАКТИРОВАТЬ: запрашивать новые идеи *****

Любые идеи, как ускорить это дальше. Я использовал метод, предложенный Алексом, чтобы сократить время пополам. Могу ли я ускорить это дальше? Спасибо.

Ответы [ 4 ]

2 голосов
/ 02 мая 2010

Я сомневаюсь, что в этом случае вы можете значительно ускориться, подняв поиск 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 голос
/ 03 мая 2010

Эта строка заставила мои глаза кровоточить:

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

Давайте сделаем его разборчивым и PEP8, а затем посмотрим, будет ли он быстрее. Первые пробелы:

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)

Хммм: 3 поиска по math.pow и 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

annnnnnd пока мы здесь, давайте избавимся от горизонтальной полосы прокрутки:

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

1 голос
/ 02 мая 2010

Методы - это просто функции, связанные с объектом:

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

Это не устраняет вызов функции, но устраняет поиск атрибутов.

1 голос
/ 02 мая 2010

Попробуйте вместо этого (при условии, что все люди одного типа Person):

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

Кроме того, вместо == None использование is None должно быть немного быстрее. Попробуйте, если поменяются and условия.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...