Improving Object Representation with __repr__
In Python, objects can be represented as strings in two different ways. These representations serve different purposes and are useful in various scenarios.
The first type is the string representation. This is created by the str() function, which is automatically called when you use the print() function. The string representation is designed to be human-readable. It presents the object in a format that is easy for us to understand and interpret.
The second type is the code representation. This is generated by the repr() function. The code representation shows the code that you would need to write to recreate the object. It's more about providing a precise and unambiguous way to represent the object in code.
Let's look at a concrete example using Python's built-in date class. This will help you see the difference between the string and code representations in action.
>>> from datetime import date
>>> d = date(2008, 7, 5)
>>> print(d) ## Uses str()
2008-07-05
>>> d ## Uses repr()
datetime.date(2008, 7, 5)
In this example, when we use print(d), Python calls the str() function on the date object d, and we get a human-readable date in the format YYYY-MM-DD. When we simply type d in the interactive shell, Python calls the repr() function, and we see the code needed to recreate the date object.
You can explicitly get the repr() string in various ways. Here are some examples:
>>> 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)
Now, let's apply this concept to our Stock class. We're going to improve the class by implementing the __repr__ method. This special method is called by Python when it needs the code representation of an object.
To do this, open the file stock.py in your editor. Then, add the __repr__ method to the Stock class. The __repr__ method should return a string that shows the code needed to recreate the Stock object.
def __repr__(self):
return f"Stock('{self.name}', {self.shares}, {self.price})"
After adding the __repr__ method, your complete Stock class should now look like this:
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
def cost(self):
return self.shares * self.price
def sell(self, shares):
self.shares -= shares
def __repr__(self):
return f"Stock('{self.name}', {self.shares}, {self.price})"
Now, let's test our modified Stock class. Open a Python interactive shell by running the following command in your terminal:
python3
Once the interactive shell is open, try the following commands:
>>> import stock
>>> goog = stock.Stock('GOOG', 100, 490.10)
>>> goog
Stock('GOOG', 100, 490.1)
You can also see how the __repr__ method works with a portfolio of stocks. Here's an example:
>>> import reader
>>> portfolio = reader.read_csv_as_instances('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)]
As you can see, the __repr__ method has made our Stock objects much more informative when displayed in the interactive shell or debugger. It now shows the code needed to recreate each object, which is very useful for debugging and understanding the state of the objects.
When you're done testing, you can exit the Python interpreter by running the following command:
>>> exit()