tags:

views:

161

answers:

4
+1  A: 

Try instead (that's assuming all persons are of the same type Person):

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

Also, instead of == None using is None should be marginally faster. Try if swapping and terms helps.

doublep
Changing `== None` to `is None` reduced the tottime from about 13 seconds to 9 seconds. Pretty good, I think. Thanks!
Curious2learn
+1  A: 

Methods are just functions bound to an object:

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

This doesn't eliminate a function call though, it eliminates an attribute lookup.

Ignacio Vazquez-Abrams
This does not reduce the timing much. However, can you explain the difference between my method and this method. What does it exactly mean, when you say that it does not prevent function call but prevents attribute lookup.Thanks!
Curious2learn
+2  A: 

I doubt you can get much speedup in this case by hoisting the lookup of person.getUtility (by class, not by instances, as other instances have pointed out). Maybe...:

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

but I suspect most of the time is actually spent in the execution of getUtility (and possibly in the lookup of p.periodCarPurchased if that's some fancy property as opposed to a plain old attribute -- I moved the latter before the and just in case it is a plain attribute and can save a number of the getUtility calls). What does your profiling say wrt the fraction of time spent in this function (net of its calls to others) vs the method (and possibly property) in question?

Alex Martelli
I think you mean `and` and not `end`
jbochi
@jbochy you're right, thanks, typo fixed.
Alex Martelli
In python (atleast <3.0), 1+True = 2, False+1 = 1. So just use `sum((p.periodCarPurchased is None and p.getUtility(theCar) >= price) for p in setOfPeople)`
Wallacoloo
@wallacoloo, that's also true in Python `3.*`, but the result is not necessarily faster since you may be summing up a lot of `0`s -- be sure to measure timing accurately before you pick one or the other.
Alex Martelli
@Alex, thanks for the suggestions. You are absolutely right...it makes sense to put the p.periodCarPurchased condition first. This change cut the time in half. Now the total time (variable tottime in the output of cprofile) in getUtility method is 1.76. Whereas tottime for the potentialActualBuyers function I have above is 12.361. That is, the potentialActualBuyers is still taking a lot of time. Though I have not yet tried the sum(...) approach that you have suggested.
Curious2learn
@curious, glad the switch helped so much -- the sum suggestions, both mine and the one in the comments, won't help as much, alas. Maybe there are implicit "fetch from db" operations going on and you could speed things up by fetching in bulk...?
Alex Martelli
@Alex, sorry, I don't understand. I am not using any database. What is "fetch from db" and "fetching in bulk". I tried the sum suggestion...that in fact slowed the run a little (by a negligible amount).
Curious2learn
+1  A: 

This one line made my eyes bleed:

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

Let's make it legible and PEP8able and then see if it can be faster. First some spaces:

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

Now we can see there are very redundant parentheses; remove them:

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

Hmmm: 3 lookups of math.pow and 3 function calls. You have three choices for powers: x ** y, the built-in pow(x, y[, z]), and math.pow(x, y). Unless you have good reason for using one of the others, it's best (IMHO) to choose x ** y; you save both the attribute lookup and the function call.

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

annnnnnd while we're here, let's get rid of the horizontal scroll-bar:

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

A possibility that would require quite a rewrite of your existing code and may not help anyway (in Python) would be to avoid most of the power calculations by taking logs everywhere and working with log_utility = log_A + log_mpg * alpha ...

John Machin
How did you get the line breaks. Did you press the `enter` key?Thanks for your suggestions.
Curious2learn
Enter key: Yes. Thanks: Have you noticed the up-pointing triangle at the top left of each answer? Ciick on this to up-vote an answer. Kind questioners up-vote all answers that they think useful, and accept (a big tick button) the answer they think most useful.
John Machin
Thanks. I did not know you could use enter for linebreak in python in the middle of an expression. I up-vote answers all the time. Before doing yours, I was waiting for your reply about the `enter` key question.
Curious2learn