title: Proper type annotation of Python functions with yield
body: <p>After reading Eli Bendersky's article <a href="http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines/">on implementing state machines via Python coroutines</a> I wanted to...</p>
  
  <ul>
  <li>see his example run under Python3</li>
  <li>and also add the appropriate type annotations for the generators</li>
  </ul>
  
  <p>I succeeded in doing the first part (<em>but without using <code>async def</code>s or <code>yield from</code>s, I basically just ported the code - so any improvements there are most welcome</em>). </p>
  
  <p>But I need some help with the type annotations of the coroutines:</p>
  
  <pre><code>#!/usr/bin/env python3
  
  from typing import Callable, Generator
  
  def unwrap_protocol(header: int=0x61,
                      footer: int=0x62,
                      dle: int=0xAB,
                      after_dle_func: Callable[[int], int]=lambda x: x,
                      target: Generator=None) -&gt; Generator:
      """ Simplified protocol unwrapping co-routine."""
      #
      # Outer loop looking for a frame header
      #
      while True:
          byte = (yield)
          frame = []  # type: List[int]
  
          if byte == header:
              #
              # Capture the full frame
              #
              while True:
                  byte = (yield)
                  if byte == footer:
                      target.send(frame)
                      break
                  elif byte == dle:
                      byte = (yield)
                      frame.append(after_dle_func(byte))
                  else:
                      frame.append(byte)
  
  
  def frame_receiver() -&gt; Generator:
      """ A simple co-routine "sink" for receiving full frames."""
      while True:
          frame = (yield)
          print('Got frame:', ''.join('%02x' % x for x in frame))
  
  bytestream = bytes(
      bytearray((0x70, 0x24,
                 0x61, 0x99, 0xAF, 0xD1, 0x62,
                 0x56, 0x62,
                 0x61, 0xAB, 0xAB, 0x14, 0x62,
                 0x7)))
  
  frame_consumer = frame_receiver()
  next(frame_consumer)  # Get to the yield
  
  unwrapper = unwrap_protocol(target=frame_consumer)
  next(unwrapper)  # Get to the yield
  
  for byte in bytestream:
      unwrapper.send(byte)
  </code></pre>
  
  <p>This runs properly...</p>
  
  <pre><code>$ ./decoder.py 
  Got frame: 99afd1
  Got frame: ab14
  </code></pre>
  
  <p>...and also typechecks:</p>
  
  <pre><code>$ mypy --disallow-untyped-defs decoder.py 
  $
  </code></pre>
  
  <p>But I am pretty sure I can do better than just use the <code>Generator</code> base class in the type specs (just as I did for the <code>Callable</code>). I know it takes 3 type parameters (<code>Generator[A,B,C]</code>), but I am not sure how exactly they'd be specified here.</p>
  
  <p>Any help most welcome.</p>