title: Why is this slicing code faster than more procedural code?
body: <p>I have a Python function that takes a list and returns a generator yielding 2-tuples of each adjacent pair, e.g.</p>
  
  <pre><code>&gt;&gt;&gt; list(pairs([1, 2, 3, 4]))
  [(1, 2), (2, 3), (3, 4)]
  </code></pre>
  
  <p>I've considered an implementation using 2 slices:</p>
  
  <pre><code>def pairs(xs):
      for p in zip(xs[:-1], xs[1:]): 
          yield p
  </code></pre>
  
  <p>and one written in a more procedural style:</p>
  
  <pre><code>def pairs(xs):
      last = object()
      dummy = last
      for x in xs:
          if last is not dummy:
              yield last,x
          last = x
  </code></pre>
  
  <p>Testing using <code>range(2 ** 15)</code> as input yields the following times (you can find my testing code and output <a href="https://gist.github.com/mambocab/c045539492f91853a29b" rel="nofollow noreferrer">here</a>):</p>
  
  <pre><code>2 slices: 100 loops, best of 3: 4.23 msec per loop
  0 slices: 100 loops, best of 3: 5.68 msec per loop
  </code></pre>
  
  <p>Part of the performance hit for the sliceless implementation is the comparison in the loop (<code>if last is not dummy</code>). Removing that (making the output incorrect) improves its performance, but it's still slower than the zip-a-pair-of-slices implementation:</p>
  
  <pre><code>2 slices: 100 loops, best of 3: 4.48 msec per loop
  0 slices: 100 loops, best of 3: 5.2 msec per loop
  </code></pre>
  
  <p>So, I'm stumped. Why is zipping together 2 slices, effectively iterating over the list twice in parallel, faster than iterating once, updating <code>last</code> and <code>x</code> as you go?</p>
  
  <p><strong>EDIT</strong></p>
  
  <p><a href="https://stackoverflow.com/a/25880602/3408454">Dan Lenski proposed</a> a third implementation:</p>
  
  <pre><code>def pairs(xs):
      for ii in range(1,len(xs)):
          yield xs[ii-1], xs[ii]
  </code></pre>
  
  <p>Here's its comparison to the other implementations:</p>
  
  <pre><code>2 slices: 100 loops, best of 3: 4.37 msec per loop
  0 slices: 100 loops, best of 3: 5.61 msec per loop
  Lenski's: 100 loops, best of 3: 6.43 msec per loop
  </code></pre>
  
  <p>It's even slower! Which is baffling to me.</p>
  
  <p><strong>EDIT 2:</strong></p>
  
  <p><a href="https://stackoverflow.com/questions/25880329/why-is-this-slicing-code-faster-than-more-procedural-code/25880602?noredirect=1#comment40502711_25880329">ssm suggested</a> using <code>itertools.izip</code> instead of <code>zip</code>, and it's even faster than <code>zip</code>:</p>
  
  <pre><code>2 slices, izip: 100 loops, best of 3: 3.68 msec per loop
  </code></pre>
  
  <p>So, <code>izip</code> is the winner so far! But still for difficult-to inspect reasons.</p>