@@ -136,10 +136,15 @@ If you want to operate on an instance, you always have to refer too it explicitl
136136
137137## Exercises
138138
139+ Note: For this exercise you want to have fully working code from earlier
140+ exercises. If things are broken look at the solution code for Exercise 3.18.
141+ You can find this code in the ` Solutions/3_18 ` directory.
142+
139143### Exercise 4.1: Objects as Data Structures
140144
141- In section 2 and 3, we worked with data represented as tuples and dictionaries.
142- For example, a holding of stock could be represented as a tuple like this:
145+ In section 2 and 3, we worked with data represented as tuples and
146+ dictionaries. For example, a holding of stock could be represented as
147+ a tuple like this:
143148
144149``` python
145150s = (' GOOG' ,100 ,490.10 )
@@ -154,125 +159,130 @@ s = { 'name' : 'GOOG',
154159}
155160```
156161
157- You can even write functions for manipulating such data. For example:
162+ You can even write functions for manipulating such data. For example:
158163
159164``` python
160165def cost (s ):
161166 return s[' shares' ] * s[' price' ]
162167```
163168
164- However, as your program gets large, you might want to create a better sense of organization.
165- Thus, another approach for representing data would be to define a class.
166-
167- Create a file called ` stock.py ` and define a class ` Stock ` that represents a single holding of stock.
168- Have the instances of ` Stock ` have ` name ` , ` shares ` , and ` price ` attributes.
169+ However, as your program gets large, you might want to create a better
170+ sense of organization. Thus, another approach for representing data
171+ would be to define a class. Create a file called ` stock.py ` and
172+ define a class ` Stock ` that represents a single holding of stock.
173+ Have the instances of ` Stock ` have ` name ` , ` shares ` , and ` price `
174+ attributes. For example:
169175
170176``` python
171177>> > import stock
172- >> > s = stock.Stock(' GOOG' ,100 ,490.10 )
173- >> > s .name
178+ >> > a = stock.Stock(' GOOG' ,100 ,490.10 )
179+ >> > a .name
174180' GOOG'
175- >> > s .shares
181+ >> > a .shares
176182100
177- >> > s .price
183+ >> > a .price
178184490.1
179185>> >
180186```
181187
182- Create a few more ` Stock ` objects and manipulate them. For example:
188+ Create a few more ` Stock ` objects and manipulate them. For example:
183189
184190``` python
185- >> > a = stock.Stock(' AAPL' ,50 ,122.34 )
186- >> > b = stock.Stock(' IBM' ,75 ,91.75 )
187- >> > a.shares * a.price
188- 6117.0
191+ >> > b = stock.Stock(' AAPL' , 50 , 122.34 )
192+ >> > c = stock.Stock(' IBM' , 75 , 91.75 )
189193>> > b.shares * b.price
194+ 6117.0
195+ >> > c.shares * c.price
1901966881.25
191- >> > stocks = [a,b,s ]
197+ >> > stocks = [a, b, c ]
192198>> > stocks
193199[< stock.Stock object at 0x 37d0b0> , < stock.Stock object at 0x 37d110> , < stock.Stock object at 0x 37d050> ]
194- >> > for t in stocks:
195- print (f ' { t .name:>10s } { t .shares:>10d } { t .price:>10.2f } ' )
200+ >> > for s in stocks:
201+ print (f ' { s .name:>10s } { s .shares:>10d } { s .price:>10.2f } ' )
196202
197203... look at the output ...
198204>> >
199205```
200206
201- One thing to emphasize here is that the class ` Stock ` acts like a factory for creating instances of objects.
202- Basically, you just call it as a function and it creates a new object for you.
207+ One thing to emphasize here is that the class ` Stock ` acts like a
208+ factory for creating instances of objects. Basically, you call
209+ it as a function and it creates a new object for you. Also, it needs
210+ to be emphasized that each object is distinct---they each have their
211+ own data that is separate from other objects that have been created.
203212
204- Also, it needs to be emphasized that each object is distinct---they
205- each have their own data that is separate from other objects that have
206- been created. An object defined by a class is somewhat similar to a
207- dictionary, just with somewhat different syntax.
208- For example, instead of writing ` s['name'] ` or ` s['price'] ` , you now
209- write ` s.name ` and ` s.price ` .
213+ An object defined by a class is somewhat similar to a dictionary--just
214+ with somewhat different syntax. For example, instead of writing
215+ ` s['name'] ` or ` s['price'] ` , you now write ` s.name ` and ` s.price ` .
210216
211- ### Exercise 4.2: Reading Data into a List of Objects
217+ ### Exercise 4.2: Adding some Methods
212218
213- In your ` stock.py ` program, write a function
214- ` read_portfolio(filename) ` that reads portfolio data from a file into
215- a list of ` Stock ` objects. This function is going to mimic the
216- behavior of earlier code you have written. Here’s how your function
217- will behave:
219+ With classes, you can attach functions to your objects. These are
220+ known as methods and are functions that operate on the data
221+ stored inside an object. Add a ` cost() ` and ` sell() ` method to your
222+ ` Stock ` object. They should work like this:
218223
219224``` python
220225>> > import stock
221- >> > portfolio = stock.read_portfolio(' Data/portfolio.csv' )
222- >> > portfolio
223- [< stock.Stock object at 0x 81d70> , < stock.Stock object at 0x 81cf0> , < stock.Stock object at 0x 81db0> ,
224- < stock.Stock object at 0x 81df0> , < stock.Stock object at 0x 81e30> , < stock.Stock object at 0x 81e70> ,
225- < stock.Stock object at 0x 81eb0> ]
226+ >> > s = stock.Stock(' GOOG' , 100 , 490.10 )
227+ >> > s.cost()
228+ 49010.0
229+ >> > s.shares
230+ 100
231+ >> > s.sell(25 )
232+ >> > s.shares
233+ 75
234+ >> > s.cost()
235+ 36757.5
226236>> >
227237```
228238
229- It is important to emphasize that ` read_portfolio() ` is a top-level function, not a method of the ` Stock ` class.
230- This function is merely creating a list of ` Stock ` objects; it’s not an operation on an individual ` Stock ` instance.
231-
232- Try performing some calculations with the above data. First, try printing a formatted table:
233-
234- ``` python
235- >> > for s in portfolio:
236- print (f ' { s.name:>10s } { s.shares:>10d } { s.price:>10.2f } ' )
237-
238- ... look at the output ...
239- >> >
240- ```
239+ ### Exercise 4.3: Creating a list of instances
241240
242- Try a list comprehension:
241+ Try these steps to make a list of Stock instances and compute the total
242+ cost:
243243
244244``` python
245- >> > more100 = [s for s in portfolio if s.shares > 100 ]
246- >> > for s in more100:
247- print (f ' { s.name:>10s } { s.shares:>10d } { s.price:>10.2f } ' )
248-
249- ... look at the output ...
245+ >> > import fileparse
246+ >> > with open (' Data/portfolio.csv' ) as lines:
247+ ... portdicts = fileparse.parse_csv(lines, select = [' name' ,' shares' ,' price' ], types = [str ,int ,float ])
248+ ...
249+ >> > portfolio = [ stock.Stock(d[' name' ], d[' shares' ], d[' price' ]) for d in portdicts]
250+ >> > portfolio
251+ [< stock.Stock object at 0x 10c9e2128> , < stock.Stock object at 0x 10c9e2048> , < stock.Stock object at 0x 10c9e2080> ,
252+ < stock.Stock object at 0x 10c9e25f8> , < stock.Stock object at 0x 10c9e2630> , < stock.Stock object at 0x 10ca6f748> ,
253+ < stock.Stock object at 0x 10ca6f7b8> ]
254+ >> > sum ([s.cost() for s in portfolio])
255+ 44671.15
250256>> >
251- ```
257+ ----
252258
253- Again, notice the similarity between ` Stock ` objects and dictionaries. They’re basically the same idea, but the syntax for accessing values differs.
259+ # ## Exercise 4.4: Using your class
254260
255- ### Exercise 4.3: Adding some Methods
261+ Modify the `read_portfolio()` function in the `report.py` program so that it
262+ reads a portfolio into a list of `Stock` instances. Once you have done that,
263+ fix all of the code in `report.py` and `pcost.py` so that it works with
264+ `Stock` instances instead of dictionaries.
256265
257- With classes, you can attach functions to your objects. These are
258- known as methods and are functions that operate on the data stored
259- inside an object.
266+ Hint: You should not have to make major changes to the code. You will mainly
267+ be changing dictionary access such as `s[' shares' ]` into `s.shares` .
260268
261- Add a ` cost() ` and ` sell() ` method to your ` Stock ` object. They should
262- work like this:
269+ You should be able to run your functions the same as before:
263270
264271```python
265- >> > import stock
266- >> > s = stock.Stock(' GOOG' ,100 ,490.10 )
267- >> > s.cost()
268- 49010.0
269- >> > s.shares
270- 100
271- >> > s.sell(25 )
272- >> > s.shares
273- 75
274- >> > s.cost()
275- 36757.5
272+ >> > import pcost
273+ >> > pcost.portfolio_cost(' Data/portfolio.csv' )
274+ 44671.15
275+ >> > import report
276+ >> > report.portfolio_report(' Data/portfolio.csv' , ' Data/prices.csv' )
277+ Name Shares Price Change
278+ ---------- ---------- ---------- ----------
279+ AA 100 9.22 - 22.98
280+ IBM 50 106.28 15.18
281+ CAT 150 35.46 - 47.98
282+ MSFT 200 20.89 - 30.34
283+ GE 95 13.48 - 26.89
284+ MSFT 50 20.89 - 44.21
285+ IBM 100 106.28 35.84
276286>> >
277287```
278288
0 commit comments