\[ [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 In link:ex3_5.html[Exercise 3.5], you made it possible for users to make 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/)