<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 <h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Yield" data-toc-modified-id="Yield-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Yield</a></span></li><li><span><a href="#Generators" data-toc-modified-id="Generators-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Generators</a></span></li><li><span><a href="#Coroutines" data-toc-modified-id="Coroutines-3"><span class="toc-item-num">3&nbsp;&nbsp;</span>Coroutines</a></span><ul class="toc-item"><li><span><a href="#Coroutine-Pipelines" data-toc-modified-id="Coroutine-Pipelines-3.1"><span class="toc-item-num">3.1&nbsp;&nbsp;</span>Coroutine Pipelines</a></span></li></ul></li><li><span><a href="#Asynchronous-Python" data-toc-modified-id="Asynchronous-Python-4"><span class="toc-item-num">4&nbsp;&nbsp;</span>Asynchronous Python</a></span><ul class="toc-item"><li><span><a href="#Event-Loop" data-toc-modified-id="Event-Loop-4.1"><span class="toc-item-num">4.1&nbsp;&nbsp;</span>Event Loop</a></span></li><li><span><a href="#Yield-From-and-Wait-(python-3.4)" data-toc-modified-id="Yield-From-and-Wait-(python-3.4)-4.2"><span class="toc-item-num">4.2&nbsp;&nbsp;</span>Yield From and Wait (python 3.4)</a></span></li><li><span><a href="#Async-and-Await-(python-3.5+)" data-toc-modified-id="Async-and-Await-(python-3.5+)-4.3"><span class="toc-item-num">4.3&nbsp;&nbsp;</span>Async and Await (python 3.5+)</a></span></li></ul></li></ul></div>
Yield
https
Step1:  Coroutines
Similar to threads, but a coroutine decides when to switch context based on the code written. Threads would switch based on the operating system (or runtime environment). Coroutines are coopertive and multitask based on how the programmer has set suspend and resume points in the code.
Similar to generators
Step2:  Coroutine Pipelines
Coroutines can be chained together to form a pipeline, starting with a producer as a simple function, going into a middle coroutine, and ending with an output coroutine. Data gets passed from one stage to another.
Step3:  Asynchronous Python
Asynchronous programming is where execution order is not 100% known ahead of time. Some parts of the code may execute before other parts, with no way to guarantee the order.
* Reference
Step4:  Async and Await (python 3.5+)
async def defines a function as asynchronous (replaces @asyncio.coroutine)
 can't contain yield, only await and return*
* this makes a function a coroutine
await keyword replaces yield from and is there to wait for a coroutine to finish
* can only be within an async def function
* calling await on an object means it has to be an awaitable object
  * i.e. it defines an __await__() method which returns an iterator which is not a coroutine itself
<ASSISTANT_TASK:>
Python Code:
def generator1(): 
    yield 1
    yield 2
    yield 3
for value in generator1():  
    print(value) 
def generator2():
    yield "Hello"
    yield "World"
my_gen = generator2()
print(next(my_gen))
print(next(my_gen))
Explanation: <h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Yield" data-toc-modified-id="Yield-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Yield</a></span></li><li><span><a href="#Generators" data-toc-modified-id="Generators-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Generators</a></span></li><li><span><a href="#Coroutines" data-toc-modified-id="Coroutines-3"><span class="toc-item-num">3&nbsp;&nbsp;</span>Coroutines</a></span><ul class="toc-item"><li><span><a href="#Coroutine-Pipelines" data-toc-modified-id="Coroutine-Pipelines-3.1"><span class="toc-item-num">3.1&nbsp;&nbsp;</span>Coroutine Pipelines</a></span></li></ul></li><li><span><a href="#Asynchronous-Python" data-toc-modified-id="Asynchronous-Python-4"><span class="toc-item-num">4&nbsp;&nbsp;</span>Asynchronous Python</a></span><ul class="toc-item"><li><span><a href="#Event-Loop" data-toc-modified-id="Event-Loop-4.1"><span class="toc-item-num">4.1&nbsp;&nbsp;</span>Event Loop</a></span></li><li><span><a href="#Yield-From-and-Wait-(python-3.4)" data-toc-modified-id="Yield-From-and-Wait-(python-3.4)-4.2"><span class="toc-item-num">4.2&nbsp;&nbsp;</span>Yield From and Wait (python 3.4)</a></span></li><li><span><a href="#Async-and-Await-(python-3.5+)" data-toc-modified-id="Async-and-Await-(python-3.5+)-4.3"><span class="toc-item-num">4.3&nbsp;&nbsp;</span>Async and Await (python 3.5+)</a></span></li></ul></li></ul></div>
Yield
https://www.geeksforgeeks.org/use-yield-keyword-instead-return-keyword-python/
Yield will suspend the execution of a function, sending a value back to the caller, but retain enough state to enable the function to resume where it left off.
* execution resumes immediately where it left off
* produce series of value over time without computing all at once and returning a list
Use yield when we want to iterate over a sequence without returning all of it at once (and having to store it all in memory). The normal return keyword would just give us everything and the function would be done.
Generators
Generators produce data - they are functions that contain the yield keyword automatically become generators. 
The generator function returns a generator object which can be iterated over:
* call the next() function with the generator as an argument
* place in a for loop
* can't accept arguments after initialized
Previously, generators had to be completely consumed by the function calling them and couldn't call another generator which would halt the execution of both. However, there is now the yield from syntax which can be used to yield the result from another generator.
End of explanation
def check_for_value(num):
    try:
        while True:
            received_value = (yield)       #data sent to this co is stored here
            if num == received_value:      #check the value that was sent
                print("Correct!")
            else:
                print("Incorrect")
    except GeneratorExit:                  #catches coroutine.close()
        print("Closing Coroutine.")
coroutine = check_for_value(42)        #instantiating the coroutine w/42
coroutine.__next__()                   #starts co and pauses at 1st yield
coroutine.send(7)
coroutine.send(42)
coroutine.close()                      #close coroutine
Explanation: Coroutines
Similar to threads, but a coroutine decides when to switch context based on the code written. Threads would switch based on the operating system (or runtime environment). Coroutines are coopertive and multitask based on how the programmer has set suspend and resume points in the code.
Similar to generators: 
* extra methods
* tweaked yield statement
* Coroutines also consume data
* can accept arguments after it's initialized
With a modified yield statement, data can be sent to a coroutine:
End of explanation
def producer(data_in, next_coroutine):
    tokens = data_in.split(" ")
    for token in tokens:
        next_coroutine.send(token)
    next_coroutine.close()
def middle_coroutine(filter_str, next_coroutine):
    print("Search for words containing: ", filter_str)
    try:
        while True:
            token = (yield)
            if filter_str in token:
                next_coroutine.send(token)
    except GeneratorExit:
        print("Done filtering")
        next_coroutine.close()
def output_coroutine():
    try:
        while True:
            token = (yield)
            print(token)
    except GeneratorExit:
        print("Done printing")
sink = output_coroutine()
sink.__next__()
middle = middle_coroutine("t", sink)
middle.__next__()
input_str = "This is a sentence with some words containing the letter t."
producer(input_str, middle)
Explanation: Coroutine Pipelines
Coroutines can be chained together to form a pipeline, starting with a producer as a simple function, going into a middle coroutine, and ending with an output coroutine. Data gets passed from one stage to another.
End of explanation
import asyncio
# Borrowed from http://curio.readthedocs.org/en/latest/tutorial.html.
@asyncio.coroutine
def countdown(number, n):
    while n > 0:
        print('T-minus', n, '({})'.format(number))
        yield from asyncio.sleep(1)
        n -= 1
asyncio.set_event_loop(asyncio.new_event_loop())
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(countdown("A", 2)), asyncio.ensure_future(countdown("B", 3))]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
Explanation: Asynchronous Python
Asynchronous programming is where execution order is not 100% known ahead of time. Some parts of the code may execute before other parts, with no way to guarantee the order.
* Reference: https://snarky.ca/how-the-heck-does-async-await-work-in-python-3-5
Event Loop
Programming construct that waits for events to happen and dispatches responses to them. The asyncio library was added to python to provide an event loop.
Yield From and Wait (python 3.4)
Reference: https://hackernoon.com/asynchronous-python-45df84b82434
Use the decorator "@asyncio.coroutine" on the generator (function) and it will now be a coroutine meant for use with asyncio and its event loop (it can also call another generator)
* use the keywords yield from instead of just yield
* line containing yield from blocks until it's completely finished, then moves on
End of explanation
import asyncio
# Borrowed from http://curio.readthedocs.org/en/latest/tutorial.html.
async def countdown(number, n):
    while n > 0:
        print('T-minus', n, '({})'.format(number))
        await asyncio.sleep(1)
        n -= 1
asyncio.set_event_loop(asyncio.new_event_loop())
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(countdown("A", 2)), asyncio.ensure_future(countdown("B", 3))]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
Explanation: Async and Await (python 3.5+)
async def defines a function as asynchronous (replaces @asyncio.coroutine)
 can't contain yield, only await and return*
* this makes a function a coroutine
await keyword replaces yield from and is there to wait for a coroutine to finish
* can only be within an async def function
* calling await on an object means it has to be an awaitable object
  * i.e. it defines an __await__() method which returns an iterator which is not a coroutine itself
End of explanation
<END_TASK>