\[ [Index](index.md) | [Exercise 8.2](ex8_2.md) | [Exercise 8.4](ex8_4.md) \] # Exercise 8.3 *Objectives:* - Using coroutines to set up processing pipelines *Files Created:* `cofollow.py`, `coticker.py` **Note** For this exercise the `stocksim.py` program should still be running in the background. In [Exercise 8.2](ex8_2.md) you wrote some code that used generators to set up a processing pipeline. A key aspect of that program was the idea of data flowing between generator functions. A very similar kind of dataflow can be set up using coroutines. The only difference is that with a coroutine, you send data into different processing elements as opposed to pulling data out with a for-loop. ## (a) A coroutine example Getting started with coroutines can be a little tricky. Here is an example program that performs the same task as [Exercise 8.2](ex8_2.md), but with coroutines. Take this program and copy it into a file called `cofollow.py`. ```python # cofollow.py import os import time # Data source def follow(filename,target): with open(filename,'r') as f: f.seek(0,os.SEEK_END) while True: line = f.readline() if line != '': target.send(line) else: time.sleep(0.1) # Decorator for coroutine functions from functools import wraps def consumer(func): @wraps(func) def start(*args,**kwargs): f = func(*args,**kwargs) f.send(None) return f return start # Sample coroutine @consumer def printer(): while True: item = yield # Receive an item sent to me print(item) # Example use if __name__ == '__main__': follow('Data/stocklog.csv',printer()) ``` Run this program and make sure produces output.. Make sure you understand how the different pieces are hooked together. ## (b) Build some pipeline components In a file `coticker.py`, build a series of pipeline components that carry out the same tasks as the `ticker.py` program in [Exercise 8.2](ex8_2.md). Here is the implementation of the various pieces. ```python # coticker.py from structure import Structure class Ticker(Structure): name = String() price =Float() date = String() time = String() change = Float() open = Float() high = Float() low = Float() volume = Integer() from cofollow import consumer, follow from tableformat import create_formatter import csv # This one is tricky. See solution for notes about it @consumer def to_csv(target): def producer(): while True: yield line reader = csv.reader(producer()) while True: line = yield target.send(next(reader)) @consumer def create_ticker(target): while True: row = yield target.send(Ticker.from_row(row)) @consumer def negchange(target): while True: record = yield if record.change < 0: target.send(record) @consumer def ticker(fmt, fields): formatter = create_formatter(fmt) formatter.headings(fields) while True: rec = yield row = [getattr(rec, name) for name in fields] formatter.row(row) ``` Your challenge: Write the main program that hooks all of these components together to generate the same stock ticker as in the previous exercise. \[ [Solution](soln8_3.md) | [Index](index.md) | [Exercise 8.2](ex8_2.md) | [Exercise 8.4](ex8_4.md) \] ---- `>>>` Advanced Python Mastery `...` A course by [dabeaz](https://www.dabeaz.com) `...` Copyright 2007-2023 ![](https://i.creativecommons.org/l/by-sa/4.0/88x31.png). This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)