[ Index | Exercise 3.5 | Exercise 3.7 ]
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
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:
>>> 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:
>>> 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:
>>> 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:
>>> 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)]
>>>
What happens if you create two identical Stock
objects and try to compare them? Find out:
>>> 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:
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.
In Exercise 3.5, you made it possible for users to make nicely formatted tables. For example:
>>> 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:
>>> 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:
>>> 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 | Index | Exercise 3.5 | Exercise 3.7 ]
>>>
Advanced Python Mastery
...
A course by dabeaz
...
Copyright 2007-2023
. This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License