Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Custom Data Types

When you pass an object to print(), it converts it to a string using the str() function. You can create a __str__() method on your custom objects to change what is output:

Python
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f'Person({self.name})'

Here’s what you’ll get:

Python
>>> from person import Person
>>> john = Person('John Cleese', 80)
>>> print(john)
Person(John Cleese)

The __str__() method is meant to output a human-readable version of your object. There is also a __repr__() method, which is meant for a Python representation of the object. There is a repr() function that corresponds to the str() function. If you define your __repr__() properly, then eval() can be called on its result to create a new object.

Python
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f'Person({self.name})'

    def __repr__(self):
        return f"Person(name='{self.name}', age={self.age})"

Here’s what you’ll get:

Python
>>> john = Person('John Cleese', age=80)
>>> repr(john)
"Person(name='John Cleese', age=80)"
>>> john2 = eval(repr(john))
>>> type(john2)
<class 'repr_person.Person'>
>>> id(john)
4472330616
>>> id(john2)
4472331736

Some collection objects, such as lists, call repr() on their contents when they are turned into strings. This can make an object printed to the screen behave differently when it is on its own compared to when it is in the list:

Python
class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

    def __str__(self):
        return self.username

    def __repr__(self):
        return f"User(username='{self.username}', password='{self.password}')"

Here’s what you’ll get:

Python
>>> from user import User
>>> u = User('jcleese', 'ParrotIsNoMore')
>>> str(u)
'jcleese'
>>> str([u])
"[User(username='jcleese', password='ParrotIsNoMore')]"

00:00 In the previous lesson, I showed you how to use print() to write to a file. In this one, I’m going to show you how to customize your classes to affect what gets printed when your object gets passed into the print() function.

00:13 print() converts its arguments to strings using str(). You’ve seen this in previous lessons. The str() method looks for two methods defined on a class to help it to know how to convert to a string.

00:26 The first is .__str__(). The second is .__repr__(). Just a quick note: because double underscore is so hard to say, a lot of programmers—or at least the cool kids—will refer to this as dunder.

00:40 So, the two methods you can define on a class are .__str__() (dunder string) and .__repr__() (dunder repr). If the str() method can’t find .__str__() or .__repr__(), it just uses a built-in default.

00:53 The guidelines state that .__str__() should be used for human-readable content. By contrast, .__repr__() is used to include far more detailed information. In fact, the Python documentation says that you should be able to pass .__repr__() to the eval() method and have it create the object itself.

01:13 I’ll show you what this looks like inside of a REPL.

01:17 For instance, let’s say you have a simple class Person that defines a name and an age and stores them on the object.

01:27 If I have this inside of a file called person and I import it, I can create an object with 'John Cleese' with an age of 80. Now, because I have not defined .__str__(), print() uses the default method.

01:43 The ugly number at the end there is an object identifier. That’s actually specific to the CPython implementation. If you’re using a different kind of Python, that string might actually look different. Now, because this is so ugly let’s add a .__str__() method to our class.

02:04 Now reprint john, and str() is now calling .__str__(), which then is a pretty, formatted string—and this is a much more useful piece of information to have show up when you print your object. Now I’ve modified the Person object, adding a .__repr__(). Once again, I can create this Person, no difference from before.

02:30 Just like str(), there’s a built-in method called repr(). If I called repr() on john, it shows what will come back from the .__repr__() of the Person object. If you look at this closely, you’ll notice that what is returning from .__repr__() in this case is valid Python code.

02:51 This is different from what’s in .__str__().

02:58 I can eval() the repr() value and create a new object. If you haven’t seen eval() before, it’s a built-in function that takes a string, treats it as Python code, and attempts to run it.

03:12 Generally, eval() is considered dangerous, particularly if you’re taking input from users. They would be able to change your code on the fly.

03:19 But this case shows you how you can actually take something from the .__repr__() result and evaluate it, creating the new object.

03:30 If I ask Python what the type is, it’s a class of a Person. If I ask for the id()this is the same as the ID that the default str() spits out—I get one number on the original john object and a different number on the new john2 object, which shows you the eval() has used the string to create a brand new object.

03:52 Let’s look at this one more time. This time, there’s a User object taking a username and password, and I’ve defined both a .__str__() and a .__repr__() method.

04:05 Like before, import the User, create a User object.

04:13 Calling str() on it will show you the .username. Something that’s a little tricky though, is that some container objects will call the repr() directly rather than the str() method. If I make the same call but on a list of users instead, the repr() gets called. The str() method of a list calls the repr() method of each of the items inside of the list. In this particular case, that would be exposing the password, which isn’t a good idea.

04:45 print() is one of the more obvious changes between Python 2 and Python 3. In the next lesson, I’ll talk about these differences and how you can take advantage of the new features in Python 3.

Avatar image for akolal

akolal on Jan. 7, 2021

I am having a real tough time seeing a dark blue font against a black background in the repl. Perhaps it is just me. But the choice in other videos were great. Please consider changing it.

Avatar image for Christopher Trudeau

Christopher Trudeau RP Team on Jan. 7, 2021

Thanks for the feedback akolal. Can I just confirm that it is the keywords like “print” or “<stdin>” that are too dark? Or are there others colours that are problematic as well?

Become a Member to join the conversation.