If/then style question

Francesco fal at togliquesto.fastwebnet.it
Tue Dec 21 14:54:02 EST 2010


I'd bet you would stress your point Steven! But you don't need to persuade me, I do already agree.
I just meant to say that, when the advantage is little, there's no need to rewrite a working function.
And that with modern CPUs, if tests take so little time, that even some redundant one is not so much of a nuisance.
in your working example, the "payload" is just a couple of integer calculations, that take very little time too. So the overhead due 
to redundant if tests does show clearly. And also in that not-really-real situation, 60% overhead just meant less than 3 seconds. 
Just for the sake of discussion, I tried to give both functions some plough to pull, and a worst-case situation too:

 >>> t1 = Timer('for x in range(100): print func1(0),',
...  'from __main__ import func1')
 >>>
 >>> t2 = Timer('for x in range(100): print func2(0),',
...  'from __main__ import func2')
 >>>
 >>> min(t1.repeat(number=1, repeat=1))
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1
53.011015366479114
 >>> min(t2.repeat(number=1, repeat=1))
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1
47.55442856564332

that accounts for a scant 11% overhead, on more than one million tests per cycle.

That said,  let's make really clear that I would heartily prefer func2 to func1, based both on readability and speed. Thank you for 
having spent some time playing with me!
Francesco

On 19/12/2010 1.05, Steven D'Aprano wrote:
> Well, let's try it with a working (albeit contrived) example. This is
> just an example -- obviously I wouldn't write the function like this in
> real life, I'd use a while loop, but to illustrate the issue it will do.
>
> def func1(n):
>      result = -1
>      done = False
>      n = (n+1)//2
>      if n%2 == 1:
>          result = n
>          done = True
>      if not done:
>          n = (n+1)//2
>          if n%2 == 1:
>              result = n
>              done = True
>      if not done:
>          n = (n+1)//2
>          if n%2 == 1:
>              result = n
>              done = True
>      if not done:
>          for i in range(1000000):
>              if not done:
>                  n = (n+1)//2
>                  if n%2 == 1:
>                      result = n
>                      done = True
>      return result
>
>
> def func2(n):
>      n = (n+1)//2
>      if n%2 == 1:
>          return n
>      n = (n+1)//2
>      if n%2 == 1:
>          return n
>      n = (n+1)//2
>      if n%2 == 1:
>          return n
>      for i in range(1000000):
>          n = (n+1)//2
>          if n%2 == 1:
>              return n
>      return -1
>
>
> Not only is the second far more readable that the first, but it's also
> significantly faster:
>
>>>> from timeit import Timer
>>>> t1 = Timer('for i in range(20): x = func1(i)',
> ... 'from __main__ import func1')
>>>> t2 = Timer('for i in range(20): x = func2(i)',
> ... 'from __main__ import func2')
>>>> min(t1.repeat(number=10, repeat=5))
> 7.3219029903411865
>>>> min(t2.repeat(number=10, repeat=5))
> 4.530779838562012
>
> The first function does approximately 60% more work than the first, all
> of it unnecessary overhead.
>
>
>




More information about the Python-list mailing list