Thursday, 10 December 2015

Difference between __str__ and __repr__ methods in python.

__str__- and __repr__-Methods

We will have a short break in our treatise on data abstraction for a quick side-trip. We want to introduce two important magic methods "__str__" and "__repr__", which we will need in future examples. In the course of this tutorial, we have already encountered the __str__ method. We had seen that we can depict various data as string by using the str function, which uses "magically" the internal __str__ method of the corresponding data type. __repr__is similar. It also produces a string representation. 

>>> l = ["Python", "Java", "C++", "Perl"]
>>> print(l)
['Python', 'Java', 'C++', 'Perl']
>>> str(l)
"['Python', 'Java', 'C++', 'Perl']"
>>> repr(l)
"['Python', 'Java', 'C++', 'Perl']"
>>> d = {"a":3497, "b":8011, "c":8300}
>>> print(d)
{'a': 3497, 'c': 8300, 'b': 8011}
>>> str(d)
"{'a': 3497, 'c': 8300, 'b': 8011}"
>>> repr(d)
"{'a': 3497, 'c': 8300, 'b': 8011}"
>>> x = 587.78
>>> str(x)
'587.78'
>>> repr(x)
'587.78'
>>> 

If you apply str or repr to an object, Python is looking for a corresponding method __str__ or __repr__ in the class definition of the object. If the method does exist, it will be called. 
In the following example, we define a class A, having neither a __str__ nor a __repr__ method. We want to see, what happens, if we use print directly on an instance of this class, or if we apply str or repr to this instance: 

>>> class A:
...     pass
... 
>>> a = A()
>>> print(a)
<__main__.A object at 0xb720a64c>
>>> print(repr(a))
<__main__.A object at 0xb720a64c>
>>> print(str(a))
<__main__.A object at 0xb720a64c>
>>> a
<__main__.A object at 0xb720a64c>
>>> 

As both methods are not available, Python uses the default output for our object "a". 

If a class has a __str__ method, the method will be used for an instance x of that class, if either the function str is applied to it or if it is used in a print function. __str__ will not be used, if repr is called, or if we try to output the value directly in an interactive Python shell: 

>>> class A:
...     def __str__(self):
...         return "42"
... 
>>> a = A()

>>> print(repr(a))
<__main__.A object at 0xb720a4cc>
>>> print(str(a))
42
>>> a
<__main__.A object at 0xb720a4cc>


Otherwise, if a class has only the __repr__ method and no __str__ method, __repr__ will be applied in the situations, where __str__would be applied, if it were available:
>>> class A:
...     def __repr__(self):
...         return "42"
... 
>>> a = A()
>>> print(repr(a))
42
>>> print(str(a))
42
>>> a
42
A frequently asked question is when to use __repr__ annd when __str__. __str__ is always the right choice, if the output should be for the end user or in other words, if it should be nicely printed. __repr__ on the other hand is used for the internal representation of an object. The output of __repr__ should be - if feasible - a string which can be parsed by the python interpreter. The result of this parsing is in an equal object. 
This means that the following should be true for an object "o": 

o == eval(repr(o)) 

This is shown in the following interactive Python session:
>>> l = [3,8,9]
>>> s = repr(l)
>>> s
'[3, 8, 9]'
>>> l == eval(s)
True
>>> l == eval(str(l))
True
>>>
We show in the following example with the datetime module that eval can only be applied on the strings created by repr: 

>>> import datetime
>>> today = datetime.datetime.now()
>>> str_s = str(today)
>>> eval(str_s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    2014-01-26 17:35:39.215144
          ^
SyntaxError: invalid token
>>> repr_s = repr(today)
>>> t = eval(repr_s)
>>> type(t)
<class 'datetime.datetime'>
>>> 

We can see that eval(repr_s) returns again a datetime.datetime object. The String created by str can't be turned into a datetime.datetime object by parsing it. 

We want to extend our robot class with a repr method. We dropped the other methods to keep this example simple: 

class Robot:

    def __init__(self, name, build_year):
        self.name = name
        self.build_year = build_year

    def __repr__(self):
        return "Robot(\"" + self.name + "\"," +  str(self.build_year) +  ")"
     
if __name__ == "__main__":
    x = Robot("Marvin", 1979)
        
    x_str = str(x)
    print(x_str)
    print("Type of x_str: ", type(x_str))
    new = eval(x_str)
    print(new)
    print("Type of new:", type(new))

x_str has the value Robot("Marvin",1979). eval(x_str) converts it again into a Robot instance. 

The script returns the following output: 

$ python3 robot_class5.py 
Robot("Marvin",1979)
Type of x_str:   <class 'str'>
Robot("Marvin",1979)
Type of new: <class '__main__.Robot'>

Now it's time to extend our class with a user friendly __str__ method: 

class Robot:

    def __init__(self, name, build_year):
        self.name = name
        self.build_year = build_year

    def __repr__(self):
        return "Robot(\"" + self.name + "\"," +  str(self.build_year) +  ")"

    def __str__(self):
        return "Name: " + self.name + ", Build Year: " +  str(self.build_year)
     
if __name__ == "__main__":
    x = Robot("Marvin", 1979)
        
    x_str = str(x)
    print(x_str)
    print("Type of x_str: ", type(x_str))
    new = eval(x_str)
    print(new)
    print("Type of new:", type(new))

When we start this program, we can see that it is not possible to convert our string x_str, created via str(x), into a Robot object anymore. 

$ python3 robot_class6.py
Name: Marvin, Build Year: 1979
Type of x_str:  <class 'str'>
Traceback (most recent call last):
  File "robot_class6.py", line 19, in <module>
    new = eval(x_str)
  File "<string>", line 1
    Name: Marvin, Build Year: 1979
        ^
SyntaxError: invalid syntax

We show in the following program that x_repr can still be turned into a Robot object: 

class Robot:

    def __init__(self, name, build_year):
        self.name = name
        self.build_year = build_year

    def __repr__(self):
        return "Robot(\"" + self.name + "\"," +  str(self.build_year) +  ")"

    def __str__(self):
        return "Name: " + self.name + ", Build Year: " +  str(self.build_year)
     
if __name__ == "__main__":
    x = Robot("Marvin", 1979)
    
    x_repr = repr(x)
    print(x_repr, type(x_repr))
    new = eval(x_repr)
    print(new)
    print("Type of new:", type(new))

The output looks like this: 

$ python3 robot_class6b.py 
Robot("Marvin",1979) <class 'str'>
Name: Marvin, Build Year: 1979
Type of new: <class '__main__.Robot'>
Source:http://www.python-course.eu/python3_object_oriented_programming.php

18 comments: