python-mastery/Exercises/ex3_6.md

174 lines
5.1 KiB
Markdown
Raw Normal View History

2023-07-17 03:21:00 +02:00
\[ [Index](index.md) | [Exercise 3.5](ex3_5.md) | [Exercise 3.7](ex3_7.md) \]
# Exercise 3.6
*Objectives:*
- Learn how to customize the behavior of objects by redefining special methods.
- Change the way that user-defined objects get printed
- Make objects comparable
- Create a context manager
*Files Created:* None
*Files Modified:* `stock.py`
## (a) Better output for representing objects
All Python objects have two string representations. The first
representation is created by string conversion via `str()`
(which is called by `print`). The string representation is
usually a nicely formatted version of the object meant for humans.
The second representation is a code representation of the object
created by `repr()` (or simply by viewing a value in the
interactive shell). The code representation typically shows you the
code that you have to type to get the object. Here is an example
that illustrates using dates:
```python
>>> from datetime import date
>>> d = date(2008, 7, 5)
>>> print(d) # uses str()
2008-07-05
>>> d # uses repr()
datetime.date(2008, 7, 5)
>>>
```
There are several techniques for obtaining the `repr()` string
in output:
```python
>>> print('The date is', repr(d))
The date is datetime.date(2008, 7, 5)
>>> print(f'The date is {d!r}')
The date is datetime.date(2008, 7, 5)
>>> print('The date is %r' % d)
The date is datetime.date(2008, 7, 5)
>>>
```
Modify the `Stock` object that you've created so that
the `__repr__()` method
produces more useful output. For example:
```python
>>> goog = Stock('GOOG', 100, 490.10)
>>> goog
Stock('GOOG', 100, 490.1)
>>>
```
See what happens when you read a portfolio of stocks and view the
resulting list after you have made these changes. For example:
```python
>>> import stock, reader
>>> portfolio = reader.read_csv_as_instances('Data/portfolio.csv', stock.Stock)
>>> portfolio
[Stock('AA', 100, 32.2), Stock('IBM', 50, 91.1), Stock('CAT', 150, 83.44), Stock('MSFT', 200, 51.23),
Stock('GE', 95, 40.37), Stock('MSFT', 50, 65.1), Stock('IBM', 100, 70.44)]
>>>
```
## (b) Making objects comparable
What happens if you create two identical `Stock` objects and try to compare them? Find out:
```python
>>> a = Stock('GOOG', 100, 490.1)
>>> b = Stock('GOOG', 100, 490.1)
>>> a == b
False
>>>
```
You can fix this by giving the `Stock` class an `__eq__()` method. For example:
```python
class Stock:
...
def __eq__(self, other):
return isinstance(other, Stock) and ((self.name, self.shares, self.price) ==
(other.name, other.shares, other.price))
...
```
Make this change and try comparing two objects again.
## (c) A Context Manager
2023-07-17 17:41:16 +02:00
In [Exercise 3.5](ex3_5.md), you made it possible for users to make
2023-07-17 03:21:00 +02:00
nicely formatted tables. For example:
```python
>>> from tableformat import create_formatter
>>> formatter = create_formatter('text')
>>> print_table(portfolio, ['name','shares','price'], formatter)
name shares price
---------- ---------- ----------
AA 100 32.2
IBM 50 91.1
CAT 150 83.44
MSFT 200 51.23
GE 95 40.37
MSFT 50 65.1
IBM 100 70.44
>>>
```
One issue with the code is that all tables are printed to standard out
(`sys.stdout`). Suppose you wanted to redirect the output to a file
or some other location. In the big picture, you might modify all of
the table formatting code to allow a different output file. However,
in a pinch, you could also solve this with a context manager.
Define the following context manager:
```python
>>> import sys
>>> class redirect_stdout:
def __init__(self, out_file):
self.out_file = out_file
def __enter__(self):
self.stdout = sys.stdout
sys.stdout = self.out_file
return self.out_file
def __exit__(self, ty, val, tb):
sys.stdout = self.stdout
```
This context manager works by making a temporary patch to `sys.stdout` to cause
all output to redirect to a different file. On exit, the patch is reverted.
Try it out:
```python
>>> from tableformat import create_formatter
>>> formatter = create_formatter('text')
>>> with redirect_stdout(open('out.txt', 'w')) as file:
tableformat.print_table(portfolio, ['name','shares','price', formatter)
file.close()
>>> # Inspect the file
>>> print(open('out.txt').read())
name shares price
---------- ---------- ----------
AA 100 32.2
IBM 50 91.1
CAT 150 83.44
MSFT 200 51.23
GE 95 40.37
MSFT 50 65.1
IBM 100 70.44
>>>
```
\[ [Solution](soln3_6.md) | [Index](index.md) | [Exercise 3.5](ex3_5.md) | [Exercise 3.7](ex3_7.md) \]
----
`>>>` Advanced Python Mastery
`...` A course by [dabeaz](https://www.dabeaz.com)
`...` Copyright 2007-2023
![](https://i.creativecommons.org/l/by-sa/4.0/88x31.png). This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)