[Tutor] Performance of classes

Kent Johnson kent37 at tds.net
Sun Jun 18 15:06:37 CEST 2006


Ismael Garrido wrote:
> Hello
> 
> I'm writing a program to find an appropiate combination of resistances 
> to obtain a desired value of resistance. The program takes into account 
> how many resistances you have available and their resistance in ohms.
> 
> Since this problem (as far as I can tell) requires to generate all 
> possible combinations (eliminating those that are impossible -ie: 
> requires 3 resistances of type A and you only have 2-), I'm trying to 
> make it run as fast as possible. So far I discovered that:
> - Calling functions that return a value (ie: just "return 
> self.something") is slower than just grabbing the value from the class

Yes, there is a cost to calling a function.

> - If you've got recursions, and you call them multiple times, you better 
> remember what they returned last time, otherwise it can consume a lot of 
> time (or to put it another way: don't go down the same road twice :)

This is the basic idea behind dynamic programming algorithms.

> - Psyco is nice :)
> - The Python Profiler is really useful in these cases :)
> 
> Now, I was reading about decorators and noticed that some classes can 
> inherit from object. I thought it should make no difference in speed, 
> but, just because, I tried changing my class to inherit from object. Big 
> surprise, it *does* change things. I was wondering if somebody could 
> explain why it does? I find it quite weird!

Inheriting from object makes your class a "new-style class" which 
changes some of the details of how the class works, so it's not really 
surprising that there is a performance difference.

> I have attached the code, I hope that's fine. If you have any further 
> optimization suggestions I would be very glad to hear them :)

generarResist() is doing a lot more work than necessary. Because i and j 
both iterate the entire list, you will generate all pairs twice. Since 
Resistencia(i,j) is equivalent to Resistencia(j,i) you would be better 
off having j just go through the part of the list starting from i. You 
can do this by iterating over indices instead of values.

Second, Resistencia(i,j).posible is going to be the same as 
Resistencia(i,j, False).posible because they use the same resistors. So 
there is no need to try Resistencia(i,j, False) if 
Resistencia(i,j).posible is False.

def generarResist(listaRes):
     resultado = []
     for i in listaRes:
         for j in listaRes:
             r = Resistencia(i,j)
             if r.posible:
                 resultado.append(r)

             r = Resistencia(i,j, False)
             if r.posible:
                 resultado.append(r)
     return unico(resultado)

Kent



More information about the Tutor mailing list