120 lines
3.2 KiB
Markdown
120 lines
3.2 KiB
Markdown
---
|
|
id: practical-python-7.11
|
|
source_exercise_id: "7.11"
|
|
title: "Class Methods in Practice"
|
|
section: "7.5 Decorated Methods"
|
|
source_path: "07_Advanced_Topics/05_Decorated_methods.md"
|
|
source_repo: "https://github.com/dabeaz-course/practical-python"
|
|
source_commit: "93dca856b41c61a0a0f85ae334116e4c125629ea"
|
|
student_visible_solution: false
|
|
has_private_solution: true
|
|
skip: false
|
|
---
|
|
|
|
# Exercise 7.11: Class Methods in Practice
|
|
|
|
> Source: Practical Python Programming, `07_Advanced_Topics/05_Decorated_methods.md`.
|
|
|
|
### Exercise 7.11: Class Methods in Practice
|
|
|
|
In your `report.py` and `portfolio.py` files, the creation of a `Portfolio`
|
|
object is a bit muddled. For example, the `report.py` program has code like this:
|
|
|
|
```python
|
|
def read_portfolio(filename, **opts):
|
|
'''
|
|
Read a stock portfolio file into a list of dictionaries with keys
|
|
name, shares, and price.
|
|
'''
|
|
with open(filename) as lines:
|
|
portdicts = fileparse.parse_csv(lines,
|
|
select=['name','shares','price'],
|
|
types=[str,int,float],
|
|
**opts)
|
|
|
|
portfolio = [ Stock(**d) for d in portdicts ]
|
|
return Portfolio(portfolio)
|
|
```
|
|
|
|
and the `portfolio.py` file defines `Portfolio()` with an odd initializer
|
|
like this:
|
|
|
|
```python
|
|
class Portfolio:
|
|
def __init__(self, holdings):
|
|
self.holdings = holdings
|
|
...
|
|
```
|
|
|
|
Frankly, the chain of responsibility is all a bit confusing because the
|
|
code is scattered. If a `Portfolio` class is supposed to contain
|
|
a list of `Stock` instances, maybe you should change the class to be a bit more clear.
|
|
Like this:
|
|
|
|
```python
|
|
# portfolio.py
|
|
|
|
import stock
|
|
|
|
class Portfolio:
|
|
def __init__(self):
|
|
self.holdings = []
|
|
|
|
def append(self, holding):
|
|
if not isinstance(holding, stock.Stock):
|
|
raise TypeError('Expected a Stock instance')
|
|
self.holdings.append(holding)
|
|
...
|
|
```
|
|
|
|
If you want to read a portfolio from a CSV file, maybe you should make a
|
|
class method for it:
|
|
|
|
```python
|
|
# portfolio.py
|
|
|
|
import fileparse
|
|
import stock
|
|
|
|
class Portfolio:
|
|
def __init__(self):
|
|
self.holdings = []
|
|
|
|
def append(self, holding):
|
|
if not isinstance(holding, stock.Stock):
|
|
raise TypeError('Expected a Stock instance')
|
|
self.holdings.append(holding)
|
|
|
|
@classmethod
|
|
def from_csv(cls, lines, **opts):
|
|
self = cls()
|
|
portdicts = fileparse.parse_csv(lines,
|
|
select=['name','shares','price'],
|
|
types=[str,int,float],
|
|
**opts)
|
|
|
|
for d in portdicts:
|
|
self.append(stock.Stock(**d))
|
|
|
|
return self
|
|
```
|
|
|
|
To use this new Portfolio class, you can now write code like this:
|
|
|
|
```
|
|
>>> from portfolio import Portfolio
|
|
>>> with open('Data/portfolio.csv') as lines:
|
|
... port = Portfolio.from_csv(lines)
|
|
...
|
|
>>>
|
|
```
|
|
|
|
Make these changes to the `Portfolio` class and modify the `report.py`
|
|
code to use the class method.
|
|
|
|
[Contents](../Contents.md) \| [Previous (7.4 Decorators)](04_Function_decorators.md) \| [Next (8 Testing and Debugging)](../08_Testing_debugging/00_Overview.md)
|
|
|
|
## 关联来源
|
|
|
|
- [[summaries/05_Decorated_methods]]
|