142 lines
3.7 KiB
Markdown
142 lines
3.7 KiB
Markdown
\[ [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
|
|
|
|
. This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)
|