Files
coding-mentor-agent/kb/python-course-kb-practical-python/wiki/exercises/4-5-an-extensibility-problem.md
T

3.2 KiB

id, source_exercise_id, title, section, source_path, source_repo, source_commit, student_visible_solution, has_private_solution, skip
id source_exercise_id title section source_path source_repo source_commit student_visible_solution has_private_solution skip
practical-python-4.5 4.5 An Extensibility Problem 4.2 Inheritance 04_Classes_objects/02_Inheritance.md https://github.com/dabeaz-course/practical-python 93dca856b41c61a0a0f85ae334116e4c125629ea false false false

Exercise 4.5: An Extensibility Problem

Source: Practical Python Programming, 04_Classes_objects/02_Inheritance.md.

Exercise 4.5: An Extensibility Problem

Suppose that you wanted to modify the print_report() function to support a variety of different output formats such as plain-text, HTML, CSV, or XML. To do this, you could try to write one gigantic function that did everything. However, doing so would likely lead to an unmaintainable mess. Instead, this is a perfect opportunity to use inheritance instead.

To start, focus on the steps that are involved in a creating a table. At the top of the table is a set of table headers. After that, rows of table data appear. Let's take those steps and put them into their own class. Create a file called tableformat.py and define the following class:

# tableformat.py

class TableFormatter:
    def headings(self, headers):
        '''
        Emit the table headings.
        '''
        raise NotImplementedError()

    def row(self, rowdata):
        '''
        Emit a single row of table data.
        '''
        raise NotImplementedError()

This class does nothing, but it serves as a kind of design specification for additional classes that will be defined shortly. A class like this is sometimes called an "abstract base class."

Modify the print_report() function so that it accepts a TableFormatter object as input and invokes methods on it to produce the output. For example, like this:

# report.py
...

def print_report(reportdata, formatter):
    '''
    Print a nicely formatted table from a list of (name, shares, price, change) tuples.
    '''
    formatter.headings(['Name','Shares','Price','Change'])
    for name, shares, price, change in reportdata:
        rowdata = [ name, str(shares), f'{price:0.2f}', f'{change:0.2f}' ]
        formatter.row(rowdata)

Since you added an argument to print_report(), you're going to need to modify the portfolio_report() function as well. Change it so that it creates a TableFormatter like this:

# report.py

import tableformat

...
def portfolio_report(portfoliofile, pricefile):
    '''
    Make a stock report given portfolio and price data files.
    '''
    # Read data files
    portfolio = read_portfolio(portfoliofile)
    prices = read_prices(pricefile)

    # Create the report data
    report = make_report_data(portfolio, prices)

    # Print it out
    formatter = tableformat.TableFormatter()
    print_report(report, formatter)

Run this new code:

>>> ================================ RESTART ================================
>>> import report
>>> report.portfolio_report('Data/portfolio.csv', 'Data/prices.csv')
... crashes ...

It should immediately crash with a NotImplementedError exception. That's not too exciting, but it's exactly what we expected. Continue to the next part.

关联来源