title: Why is python itertools "consume" recipe faster than calling next n times?
body: <p>In the python documentation for itertools it provides the following "recipe" for advancing an iterator n steps:</p>
  
  <pre><code>def consume(iterator, n):
      "Advance the iterator n-steps ahead. If n is none, consume entirely."
      # Use functions that consume iterators at C speed.
      if n is None:
          # feed the entire iterator into a zero-length deque
          collections.deque(iterator, maxlen=0)
      else:
          # advance to the empty slice starting at position n
          next(islice(iterator, n, n), None)
  </code></pre>
  
  <p>I'm wondering why this recipe is fundamentally different from something like this (aside from the handling of consuming the whole iterator):</p>
  
  <pre><code>def other_consume(iterable, n):
      for i in xrange(n):
          next(iterable, None)
  </code></pre>
  
  <p>I used <code>timeit</code> to confirm that, as expected, the above approach is much slower. What's going on in the recipe that allows for this superior performance? I get that it uses <code>islice</code>, but looking at <code>islice</code>, it APPEARS to be doing fundamentally the same thing as the code above: </p>
  
  <pre><code>def islice(iterable, *args):
      s = slice(*args)
      it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1))
      nexti = next(it)
      ### it seems as if this loop yields from the iterable n times via enumerate
      ### how is this different from calling next n times?
      for i, element in enumerate(iterable): 
          if i == nexti:
              yield element
              nexti = next(it)
  </code></pre>
  
  <p>Note: even if instead of importing <code>islice</code> from <code>itertools</code> I define it using the python equivalent from the docs shown above, the recipe is still faster..</p>
  
  <p>EDIT: <code>timeit</code> code here:</p>
  
  <pre><code>timeit.timeit('a = iter([random() for i in xrange(1000000)]); consume(a, 1000000)', setup="from __main__ import consume,random", number=10)
  timeit.timeit('a = iter([random() for i in xrange(1000000)]); other_consume(a, 1000000)', setup="from __main__ import other_consume,random", number=10)
  </code></pre>
  
  <p><code>other_consume</code> is ~ 2.5x slower each time I run this</p>