Do generators simply make new objects with __iter__ and next functions?
<p>I tried to search for this answer on my own, but there was too much noise.</p>

<p>Are generators in python just a convenience wrapper for the user to make an iterator object?</p>

<p>When you define the generator:</p>

<pre><code>def test():
  x = 0
  while True:
    x += 1
    yield x
</code></pre>

<p>is python simply making a new object, adding the <code>__iter__</code> method, then putting the rest of the code into the <code>next</code> function?</p>

<pre><code>class Test(object):

  def __init__(self):
    self.x = 0

  def __iter__(self):
    return self

  def next(self):
    self.x += 1
    return self.x
</code></pre>

<p>Nope.  Like so:</p>

<pre><code>&gt;&gt;&gt; def test():
...    x = 0
...    while True:
...       x += 1
...       yield x
...
&gt;&gt;&gt; type(test)
&lt;type 'function'&gt;
</code></pre>

<p>So what it returns is a function object.  Details from there get hairy; the short course is that the code object belonging to the function (<code>test.func_code</code>) is marked as a generator by one of the flags in <code>test.func_code.co_flags</code>.</p>

<p>You can disassemble the bytecode for <code>test</code> to see that it's just like any other function otherwise, apart from that a generator function always contains a <code>YIELD_VALUE</code> opcode:</p>

<pre><code>&gt;&gt;&gt; import dis
&gt;&gt;&gt; dis.dis(test)
  2           0 LOAD_CONST               1 (0)
              3 STORE_FAST               0 (x)

  3           6 SETUP_LOOP              25 (to 34)
        &gt;&gt;    9 LOAD_GLOBAL              0 (True)
             12 POP_JUMP_IF_FALSE       33

  4          15 LOAD_FAST                0 (x)
             18 LOAD_CONST               2 (1)
             21 INPLACE_ADD
             22 STORE_FAST               0 (x)

  5          25 LOAD_FAST                0 (x)
             28 YIELD_VALUE
             29 POP_TOP
             30 JUMP_ABSOLUTE            9
        &gt;&gt;   33 POP_BLOCK
        &gt;&gt;   34 LOAD_CONST               0 (None)
             37 RETURN_VALUE
</code></pre>

<p>To do it the way you have in mind, the horrors just start ;-) if you think about how to create an object to mimic just this:</p>

<pre><code>def test():
    yield 2
    yield 3
    yield 4
</code></pre>

<p>Now your <code>next()</code> method would have to carry additional hidden state just to remember which <code>yield</code> comes next.  Wrap that in some nested loops with some conditionals, and "unrolling" it into a single-entry <code>next()</code> becomes a nightmare.</p>

python