Generators vs. Functions?

Duncan Booth duncan.booth at invalid.invalid
Sun Feb 5 05:05:22 EST 2006


Steven D'Aprano wrote:

>>>> t1.timeit()
> 0.63980388641357422
...
>>>> t2.timeit()
> 0.82081794738769531
> 
> So on the basis of my tests, there is a small, but significant speed
> advantage to _calling_ a function versus _resuming_ a generator.

I get the same, but the difference is much less on my system:

>>> min(t1.timeit() for i in range(3))
0.43929577641858941
>>> min(t2.timeit() for i in range(3))
0.46473169075954956

You missed though what is perhaps a more representative case. Generators 
have state, so for a fair comparison you need to restore some state. I 
think a fairer comparison is:

>>> t5 = timeit.Timer(stmt="func.next()", setup=
"""class K:
   pass

   def next(self):
      return 1

func = K()
""")
>>> 
>>> min(t5.timeit() for i in range(3))
0.58508302032805659


The method call is slower than the generator resumption and that is without 
even accessing any of the saved state. If you do access the saved state the 
generator runs at about the same speed as the original (local variable 
access is about as fast as accessing a constant), but the method slows down 
even more:

>>> t6 = timeit.Timer(stmt="gen.next()", setup=
"""def g(n):
  while 1: yield n
gen = g(42)
""")
>>> min(t6.timeit() for i in range(3))
0.46405506845144373
>>> t7 = timeit.Timer(stmt="func.next()", setup=
"""class K:
   def __init__(self, n):
       self.n = n

   def next(self):
      return self.n

func = K(42)
""")
>>> min(t7.timeit() for i in range(3))
0.67426781895460408





More information about the Python-list mailing list