title: Why is Python 3 is considerably slower than Python 2?
body: <p>I've been trying to understand why Python 3 is actually taking much time compared with Python 2 in certain situations, below are few cases I've verified from python 3.4 to python 2.7.</p>
  
  <p>Note: I've gone through some of the questions like <a href="https://stackoverflow.com/questions/15014310">Why is there no xrange function in Python3?</a>  and  <a href="https://stackoverflow.com/questions/25678127">loop in python3 much slower than python2</a>  and <a href="https://stackoverflow.com/questions/14911122">Same code slower in Python3 as compared to Python2</a>, but I feel that I didn't get the actual reason behind this issue.</p>
  
  <p>I've tried this piece of code to show how it is making difference:</p>
  
  <pre><code>MAX_NUM = 3*10**7
  
  # This is to make compatible with py3.4.
  try:
      xrange
  except:
      xrange = range
  
  
  def foo():
      i = MAX_NUM
      while i&gt; 0:
          i -= 1
  
  def foo_for():
      for i in xrange(MAX_NUM):
          pass
  </code></pre>
  
  <p>When I've tried running this programme with py3.4 and py2.7 I've got below 
  results.</p>
  
  <p>Note: These stats came through a <code>64 bit</code> machine with <code>2.6Ghz</code> processor and calculated the time using <code>time.time()</code> in single loop.</p>
  
  <pre><code>Output : Python 3.4
  -----------------
  2.6392083168029785
  0.9724123477935791
  
  Output: Python 2.7
  ------------------
  1.5131521225
  0.475143909454
  </code></pre>
  
  <p>I really don't think that there has been changes applied to <code>while</code> or <code>xrange</code> from 2.7 to 3.4, I know <code>range</code> has been started acting as to <code>xrange</code> in py3.4 but as documentation says</p>
  
  <blockquote>
    <p><code>range()</code> now behaves like <code>xrange()</code> used to behave, except it works with values of arbitrary size. The latter no longer exists.</p>
  </blockquote>
  
  <p>this means change from <code>xrange</code> to <code>range</code> is very much equal to a name change but working with arbitrary values.</p>
  
  <p>I've verified disassembled byte code as well.</p>
  
  <p>Below is the disassembled byte code for function <code>foo()</code>:</p>
  
  <pre><code>Python 3.4:
  --------------- 
  
   13           0 LOAD_GLOBAL              0 (MAX_NUM)
                3 STORE_FAST               0 (i)
  
   14           6 SETUP_LOOP              26 (to 35)
          &gt;&gt;    9 LOAD_FAST                0 (i)
               12 LOAD_CONST               1 (0)
               15 COMPARE_OP               4 (&gt;)
               18 POP_JUMP_IF_FALSE       34
  
   15          21 LOAD_FAST                0 (i)
               24 LOAD_CONST               2 (1)
               27 INPLACE_SUBTRACT
               28 STORE_FAST               0 (i)
               31 JUMP_ABSOLUTE            9
          &gt;&gt;   34 POP_BLOCK
          &gt;&gt;   35 LOAD_CONST               0 (None)
               38 RETURN_VALUE
  
  python 2.7
  -------------
  
   13           0 LOAD_GLOBAL              0 (MAX_NUM)
                3 STORE_FAST               0 (i)
  
   14           6 SETUP_LOOP              26 (to 35)
          &gt;&gt;    9 LOAD_FAST                0 (i)
               12 LOAD_CONST               1 (0)
               15 COMPARE_OP               4 (&gt;)
               18 POP_JUMP_IF_FALSE       34
  
   15          21 LOAD_FAST                0 (i)
               24 LOAD_CONST               2 (1)
               27 INPLACE_SUBTRACT    
               28 STORE_FAST               0 (i)
               31 JUMP_ABSOLUTE            9
          &gt;&gt;   34 POP_BLOCK           
          &gt;&gt;   35 LOAD_CONST               0 (None)
               38 RETURN_VALUE        
  </code></pre>
  
  <p>And below is the disassembled byte code for function <code>foo_for()</code>:</p>
  
  <pre><code>Python: 3.4
  
   19           0 SETUP_LOOP              20 (to 23)
                3 LOAD_GLOBAL              0 (xrange)
                6 LOAD_GLOBAL              1 (MAX_NUM)
                9 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
               12 GET_ITER
          &gt;&gt;   13 FOR_ITER                 6 (to 22)
               16 STORE_FAST               0 (i)
  
   20          19 JUMP_ABSOLUTE           13
          &gt;&gt;   22 POP_BLOCK
          &gt;&gt;   23 LOAD_CONST               0 (None)
               26 RETURN_VALUE
  
  
  Python: 2.7
  -------------
  
   19           0 SETUP_LOOP              20 (to 23)
                3 LOAD_GLOBAL              0 (xrange)
                6 LOAD_GLOBAL              1 (MAX_NUM)
                9 CALL_FUNCTION            1
               12 GET_ITER            
          &gt;&gt;   13 FOR_ITER                 6 (to 22)
               16 STORE_FAST               0 (i)
  
   20          19 JUMP_ABSOLUTE           13
          &gt;&gt;   22 POP_BLOCK           
          &gt;&gt;   23 LOAD_CONST               0 (None)
               26 RETURN_VALUE        
  </code></pre>
  
  <p>If we compare both the byte codes they've produced the same disassembled byte code.</p>
  
  <p>Now I'm wondering what change from 2.7 to 3.4 is really causing this huge change in execution time in the given piece of code. </p>