90 lines
2.9 KiB
Markdown
90 lines
2.9 KiB
Markdown
---
|
|
id: practical-python-4.7
|
|
source_exercise_id: "4.7"
|
|
title: "Polymorphism in Action"
|
|
section: "4.2 Inheritance"
|
|
source_path: "04_Classes_objects/02_Inheritance.md"
|
|
source_repo: "https://github.com/dabeaz-course/practical-python"
|
|
source_commit: "93dca856b41c61a0a0f85ae334116e4c125629ea"
|
|
student_visible_solution: false
|
|
has_private_solution: false
|
|
skip: false
|
|
---
|
|
|
|
# Exercise 4.7: Polymorphism in Action
|
|
|
|
> Source: Practical Python Programming, `04_Classes_objects/02_Inheritance.md`.
|
|
|
|
### Exercise 4.7: Polymorphism in Action
|
|
|
|
A major feature of object-oriented programming is that you can
|
|
plug an object into a program and it will work without having to
|
|
change any of the existing code. For example, if you wrote a program
|
|
that expected to use a `TableFormatter` object, it would work no
|
|
matter what kind of `TableFormatter` you actually gave it. This
|
|
behavior is sometimes referred to as "polymorphism."
|
|
|
|
One potential problem is figuring out how to allow a user to pick out
|
|
the formatter that they want. Direct use of the class names such as
|
|
`TextTableFormatter` is often annoying. Thus, you might consider some
|
|
simplified approach. Perhaps you embed an `if-`statement into the
|
|
code like this:
|
|
|
|
```python
|
|
def portfolio_report(portfoliofile, pricefile, fmt='txt'):
|
|
'''
|
|
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
|
|
if fmt == 'txt':
|
|
formatter = tableformat.TextTableFormatter()
|
|
elif fmt == 'csv':
|
|
formatter = tableformat.CSVTableFormatter()
|
|
elif fmt == 'html':
|
|
formatter = tableformat.HTMLTableFormatter()
|
|
else:
|
|
raise RuntimeError(f'Unknown format {fmt}')
|
|
print_report(report, formatter)
|
|
```
|
|
|
|
In this code, the user specifies a simplified name such as `'txt'` or
|
|
`'csv'` to pick a format. However, is putting a big `if`-statement in
|
|
the `portfolio_report()` function like that the best idea? It might
|
|
be better to move that code to a general purpose function somewhere
|
|
else.
|
|
|
|
In the `tableformat.py` file, add a function `create_formatter(name)`
|
|
that allows a user to create a formatter given an output name such as
|
|
`'txt'`, `'csv'`, or `'html'`. Modify `portfolio_report()` so that it
|
|
looks like this:
|
|
|
|
```python
|
|
def portfolio_report(portfoliofile, pricefile, fmt='txt'):
|
|
'''
|
|
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.create_formatter(fmt)
|
|
print_report(report, formatter)
|
|
```
|
|
|
|
Try calling the function with different formats to make sure it's working.
|
|
|
|
## 关联来源
|
|
|
|
- [[summaries/02_Inheritance]]
|