title: Differences between generator comprehension expressions
body: <p>There are, as far as I know, three ways to create a generator through a comprehension<sup>1</sup>.</p>
  <p>The classical one:</p>
  <pre><code>def f1():
      g = (i for i in range(10))
  </code></pre>
  <p>The <code>yield</code> variant:</p>
  <pre><code>def f2():
      g = [(yield i) for i in range(10)]
  </code></pre>
  <p>The <code>yield from</code> variant (that raises a <code>SyntaxError</code> except inside of a function):</p>
  <pre><code>def f3():
      g = [(yield from range(10))]
  </code></pre>
  <p>The three variants lead to different bytecode, which is not really surprising.
  It would seem logical that the first one is the best, since it's a dedicated, straightforward syntax to create a generator through comprehension.
  However, it is not the one that produces the shortest bytecode.</p>
  <p><em>Disassembled in Python 3.6</em></p>
  <p><strong>Classical generator comprehension</strong></p>
  <pre><code>&gt;&gt;&gt; dis.dis(f1)
  4           0 LOAD_CONST               1 (&lt;code object &lt;genexpr&gt; at...&gt;)
              2 LOAD_CONST               2 ('f1.&lt;locals&gt;.&lt;genexpr&gt;')
              4 MAKE_FUNCTION            0
              6 LOAD_GLOBAL              0 (range)
              8 LOAD_CONST               3 (10)
             10 CALL_FUNCTION            1
             12 GET_ITER
             14 CALL_FUNCTION            1
             16 STORE_FAST               0 (g)
  
  5          18 LOAD_FAST                0 (g)
             20 RETURN_VALUE
  </code></pre>
  <p><strong><code>yield</code> variant</strong></p>
  <pre><code>&gt;&gt;&gt; dis.dis(f2)
  8           0 LOAD_CONST               1 (&lt;code object &lt;listcomp&gt; at...&gt;)
              2 LOAD_CONST               2 ('f2.&lt;locals&gt;.&lt;listcomp&gt;')
              4 MAKE_FUNCTION            0
              6 LOAD_GLOBAL              0 (range)
              8 LOAD_CONST               3 (10)
             10 CALL_FUNCTION            1
             12 GET_ITER
             14 CALL_FUNCTION            1
             16 STORE_FAST               0 (g)
  
  9          18 LOAD_FAST                0 (g)
             20 RETURN_VALUE
  </code></pre>
  <p><strong><code>yield from</code> variant</strong></p>
  <pre><code>&gt;&gt;&gt; dis.dis(f3)
  12           0 LOAD_GLOBAL              0 (range)
               2 LOAD_CONST               1 (10)
               4 CALL_FUNCTION            1
               6 GET_YIELD_FROM_ITER
               8 LOAD_CONST               0 (None)
              10 YIELD_FROM
              12 BUILD_LIST               1
              14 STORE_FAST               0 (g)
  
  13          16 LOAD_FAST                0 (g)
              18 RETURN_VALUE
          
  </code></pre>
  <hr />
  <p>In addition, a <code>timeit</code> comparison shows that the <code>yield from</code> variant is the fastest (still run with Python 3.6):</p>
  <pre><code>&gt;&gt;&gt; timeit(f1)
  0.5334039637357152
  
  &gt;&gt;&gt; timeit(f2)
  0.5358906506760719
  
  &gt;&gt;&gt; timeit(f3)
  0.19329123352712596
  </code></pre>
  <p><code>f3</code> is more or less 2.7 times as fast as <code>f1</code> and <code>f2</code>.</p>
  <p>As <strong>Leon</strong> mentioned in a comment, the efficiency of a generator is best measured by the speed it can be iterated over.
  So I changed the three functions so they iterate over the generators, and call a dummy function.</p>
  <pre><code>def f():
      pass
  
  def fn():
      g = ...
      for _ in g:
          f()
  </code></pre>
  <p>The results are even more blatant:</p>
  <pre><code>&gt;&gt;&gt; timeit(f1)
  1.6017412817975778
  
  &gt;&gt;&gt; timeit(f2)
  1.778684261368946
  
  &gt;&gt;&gt; timeit(f3)
  0.1960603619517669
  </code></pre>
  <p><code>f3</code> is now 8.4 times as fast as <code>f1</code>, and 9.3 times as fast as <code>f2</code>.</p>
  <p><strong>Note:</strong> The results are more or less the same when the iterable is not <code>range(10)</code> but a static iterable, such as <code>[0, 1, 2, 3, 4, 5]</code>.
  Therefore, the difference of speed has nothing to do with <code>range</code> being somehow optimized.</p>
  <hr />
  <p>So, what are the differences between the three ways?
  More specifically, what is the difference between the <code>yield from</code> variant and the two other?</p>
  <p>Is this normal behaviour that the natural construct <code>(elt for elt in it)</code> is slower than the tricky <code>[(yield from it)]</code>?
  Shall I from now on replace the former by the latter in all of my scripts, or is there any drawbacks to using the <code>yield from</code> construct?</p>
  <hr />
  <h3>Edit</h3>
  <p>This is all related, so I don't feel like opening a new question, but this is getting even stranger.
  I tried comparing <code>range(10)</code> and <code>[(yield from range(10))]</code>.</p>
  <pre><code>def f1():
      for i in range(10):
          print(i)
      
  def f2():
      for i in [(yield from range(10))]:
          print(i)
  
  &gt;&gt;&gt; timeit(f1, number=100000)
  26.715589237537195
  
  &gt;&gt;&gt; timeit(f2, number=100000)
  0.019948781941049987
  </code></pre>
  <p>So. Now, iterating over <code>[(yield from range(10))]</code> is 186 times as fast as iterating over a bare <code>range(10)</code>?</p>
  <p>How do you explain why iterating over <code>[(yield from range(10))]</code> is so much faster than iterating over <code>range(10)</code>?</p>
  <hr />
  <p><sup>1: For the sceptical, the three expressions that follow do produce a <code>generator</code> object; try and call <code>type</code> on them.</sup></p>