title: How yield catches StopIteration exception?
body: <p>Why in the example function terminates:</p>
  
  <pre><code>def func(iterable):
      while True:
          val = next(iterable)
          yield val
  </code></pre>
  
  <p>but if I take off yield statement function will raise StopIteration exception?</p>
  
  <p><strong>EDIT:</strong> Sorry for misleading you guys. I know what generators are and how to use them. Of course when I said function terminates I didn't mean eager evaluation of function. I just implied that when I use function to produce generator:</p>
  
  <pre><code>gen = func(iterable)
  </code></pre>
  
  <p>in case of <em>func</em> it works and returns the same generator, but in case of func2:</p>
  
  <pre><code>def func2(iterable):
      while True:
          val = next(iterable)
  </code></pre>
  
  <p>it raises StopIteration instead of <em>None</em> return or infinite loop.</p>
  
  <p>Let me be more specific. There is a function <em><a href="http://docs.python.org/2/library/itertools.html#itertools.tee" rel="noreferrer">tee</a></em> in <strong>itertools</strong> which is equivalent to:</p>
  
  <pre><code>def tee(iterable, n=2):
      it = iter(iterable)
      deques = [collections.deque() for i in range(n)]
      def gen(mydeque):
          while True:
              if not mydeque:             # when the local deque is empty
                  newval = next(it)       # fetch a new value and
                  for d in deques:        # load it to all the deques
                      d.append(newval)
              yield mydeque.popleft()
      return tuple(gen(d) for d in deques)
  </code></pre>
  
  <p>There is, in fact, some magic, because nested function <em>gen</em> has infinite loop without break statements. <em>gen</em> function terminates due to <em>StopIteration</em> exception when there is no items in <em>it</em>. But it terminates correctly (without raising exceptions), i.e. just stops loop. <strong>So the question is</strong>: where is <em>StopIteration</em> is handled?</p>