Locked learning resources

You must own this product to watch this lesson.

Locked learning resources

You must own this product to watch this lesson.

String Conversion "__repr__" vs "__str__"

00:00 Today, I want to talk about how you can control how a Python class is represented as a string, and also when you interact with it or inspect it in a Python interpreter session. So, let’s start with a really simple example here.

00:15 I’ve got my popular Car class, and we’re just going to create a simple Car object here. And what you can see is that when I print this Car object, we kind of get this unsatisfying result, and it’s the same when I just inspect the object in this interpreter session. So you can see here, well, at least it gives us the class name—kind of the whole namespace of this thing—but it only gives us the memory address, you know, if we’re on CPython, it just gives us this ID. And it’s kind of opaque and kind of hard to understand what’s going on. So, this is better than nothing, but it’s not super useful.

00:54 Now, there’s a common workaround that I see some people apply. For example, they start printing out the class attributes directly. And sure—that works, you can do that.

01:06 We can kind of pry that class apart and reach in and take out the .color and the .mileage here—that works. And then what I see some people do is they would kind of go ahead and do their own to_string() method, right?

01:20 And then that would print directly or return a string representing the class. But there is a convention inside Python that handles all of that, so you don’t have to come up with your own ways to do that because there’s actually preexisting conventions on how to do that.

01:36 So, I want to explain to you how that works. Basically what you’re going to learn today is how the .__str__() and .__repr__() methods work in Python. This is going to be a highly useful thing.

01:50 This is a common interview question. So, you know, watching this tutorial could literally pay you money in the future, so stay tuned if you don’t know how this stuff works.

02:01 Okay. So, to ease into this with a simple example, I took the same Car class and I added a .__str__() method here. So, the dunder methods are methods that start with a double underscore (__)—it’s just kind of been shortened to dunder.

02:15 Some people refer to them as magic methodsa lot of people don’t like that because they’re not really supposed to be magical in any way. They’re just supposed to be, well, a Python convention. And the dunder, or the double underscore (__), marks them as a core Python thing, so classes are not supposed to actually define their own dunder methods because it could conflict with Python features in the future.

02:38 And so this is just a way to kind of namespace these things a little bit, just by a naming convention, kind of keeping them separate a little bit, just like the .__init__() method.

02:48 But you know—total sidetrack here. So what I’ve done here is I added a .__str__() method. And basically what I did here—whenever that method is called, it just returns the .color of the Car and kind of tells us it’s a Car.

03:01 So just to show you an example here—again, I’m going to create the same Car. And now when I print this Car

03:12 I actually get a completely different result, right? So this time I get a red carwhich is the result of this .__str__() method—instead of this crazy string with the object address in memory. However, when I just inspect this object, I still get the memory address in the previous result.

03:29 So, inspecting the Car object still gives the same result, but when I printed the Car object, I got this different result based on the .__str__() method.

03:42 The way you would actually convert an object to string—if you wanted to force that or make that happen—you would just use the built-in str() method, and then that is internally going to do the right thing and call the .__str__() method, and it’s going to give you back the right result.

04:00 Now, all of these functions that deal with text representations for objects, like the print() function—they are going to do that internally.

04:08 They’re going to call the str() function for you. And it would be the same with a format string, for example. So if you do this, then this would also call .__str__() and just give you the result.

04:19 But the key thing is here that by convention, if you add a .__str__() method, then it’s going to do a lot of good for you in controlling how your object is represented as a string. So it’s the Pythonic way to do this, which is kind of the Holy Grail, right? Now, still what you’re seeing here was that when I inspected the my_car object in the console, I still got the same result.

04:45 So there seems to be different ways to convert your objects into strings. The first one we just learned about—it’s called __str__() (dunder str).

04:54 And now the second one is called __repr__() (dunder repr). Let’s talk about what .__repr__() does and how it’s different to .__str__().

05:01 In order to understand what’s going on here, I defined this class—or, kind of, redefined my Car class. And what this new version of the Car class does, it actually has a .__repr__() and a .__str__() implementation.

05:19 Now, those implementations are just dummy implementations that are going to tell us what’s going on behind the scenes. So, if something calls .__repr__() behind the scenes, we’re going to get '__repr__ for Car' as a result, and if something calls .__str__(), we’re going to get '__str__ for Car' as a result.

05:33 So now, we can walk through to the same example again and do a print(my_car). And you can see here, okay, it called the .__str__() function.

05:42 We could also go through the .format() example again—you can see it called the .__str__() function. And now, if we do my_car and just inspect that, we can see here that it’s actually called .__repr__() for the Car.

05:54 And another way to force this is to call the built-in repr() function,

06:00 and then that’s going to do the right thing and call the correct .__repr__() implementation for this. Usually, you just want to use the str() and repr() helpers for that.

06:12 Now, of course, the big question is, “Okay, so now we have these two—what’s actually the difference between them, or what’s the different use cases where you would use them?”

06:24 All right, so we have .__str__() and we have .__repr__(), and they’re both called by some convention but, you know—what’s actually the difference?

06:31 Like, shouldn’t they return the same thing? How are we going to deal with this? And the answer that I’ve got for you is let’s look at what some of the Python built-in classes from the Python standard library are doing here.

06:46 So, what I’m going to do here is I’m going to import the datetime module, and then we’re just going to create a new date object. All right, so I just created a new datetime.date object.

07:00 And then we’re going to try and experiment with that so we can see how it reacts, right? How does its .__str__() and .__repr__() function react, and what result do we get from it?

07:11 So, let’s call str() on that date object.

07:16 And you can see here, we get a pretty concise representation—it’s quite readable. It looks like an ISO date format, which is kind of the standard representation for a date in string form.

07:28 Okay, ha. And now we call repr() on the same object instance.

07:35 It actually looks quite different, because now we get a more elaborate result that is really unambiguous, right? This is not any kind of date, but we know exactly it’s a datetime.date object and it was created in this way.

07:52 And we could even copy and paste this and execute that as valid Python, and it would recreate the same object, right? Like I said earlier, when you call, when you just inspect an object in the interpreter, that also gives you the .__repr__().

08:09 This gives us a pretty good idea of the difference between .__str__() and .__repr__(). When you actually go to the Python documentation and do some reading on the best practices that people have come up with in the community, then you’ll learn that the .__str__() method—it’s mainly used for giving an easy-to-read representation of your class. All right, so .__str__() should be easy to read and it’s meant for human consumption.

08:41 So, you can see that here—it’s this ISO date. You could display that to a user and it wouldn’t be too bad. With .__repr__(), on the other hand, it should be unambiguous.

08:49 The goal here really is to be as explicit as possible about what this object is. And it’s, I guess, more meant for internal use and something that would make things easier to debug for a developer, but you wouldn’t necessarily want to display that to a user.

09:05 And so some people actually recommend that the result of your .__repr__() should be something like this, that would actually be valid Python and that you could just run again and would recreate the same object. Now, personally, I find that this is a really good idea, but it’s usually really hard to attain that in practice.

09:23 So, the bottom line is that you want your .__repr__() to be unambiguous and more meant for developers, but the .__str__()you want that to be easy to read and potentially for human consumption.

09:35 So now, there are a couple of more interesting things that I want to talk about here because they really make this whole thing a little bit easier to understand how it works in the real world. So, the next example I want to show you is an actual implementation that someone might take for their class. And because Python falls back to calling .__repr__() if you don’t define a separate .__str__() implementation, my recommendation is actually to put a .__repr__() on any class that you define, because then you get a pretty helpful and readable result in all cases, and now what I’m going to do is also give you a complete example of how you would do that, because there’s a slight trick you can apply to make this a little bit easier to work with. So again, I’ve got my Car class here, and I’m defining the .__repr__() right now, and so how I would go about doing this is, well, returning a string that contains the Car class name, and then I would probably do this self.color,

10:36 and self.mileage, right? That’s a format string, and then I would just pass the self object. Now, a common thing that I see here is that usually, you have to re-type the name of the class inside the .__repr__(), but there’s actually a way to get around that—because we can just reach into the class itself and ask it for its name.

11:01 So, what you can do here instead is you can use self.__class__.__name__. This is getting kind of long, so you want to make sure you format that in a way that’s sensible.

11:15 But basically, what this is going to do is it’s going to automatically use the right name for the class, so you don’t have to make sure you update this, right?

11:25 So, you might not want that in some cases—maybe you want the .__repr__() class name to be static—but usually, this is a good default implementation for your .__repr__().

11:35 And now, when I create a new my_car object and I inspect it, I get a really nice result.

11:42 And also, when I call str() on it or when I print the Car, I get the same result, because the default implementation for str() just calls .__repr__() internally. Okay, so this is kind of the minimum implementation I would recommend to you, where you’re adding a .__repr__() to any class that you define.

12:01 You kind of leave the .__str__() on the side and you would use something like this so you don’t have to type the class name again.

12:10 Okay, so before we wrap this up, there’s one more thing I wanted to mention, and that is how containers convert their child objects—the objects they contain—to string.

12:20 Maybe the surprising thing is that even if you call str() on a container—so, I’m creating this list object here—even if you call str() on a container, it’s going to represent the internal objects with the .__repr__() function.

12:37 So when I—you know, I’m using the today object, which is just a datetime object—or, datetime.date object. So, when I have this list here of these three date objects and then I call str() on it, I actually get a string back that has the container with the .__repr__() inside.

12:53 So, this is just something to keep in mind how that works. If you wanted to convert those with the str() function individually, you would just need a loop or some kind of list comprehension to do that manually. But you know, that’s just a side note.

13:07 I think, really, the bottom line or the one takeaway from this thing here is # At least add a __repr__ to your classes :).

13:19 All right! So, I hope you learned something new today and you’re going to be able to apply that in a real-world program or in some code that you write. Cool!

13:27 Well, happy Pythoning, and I’ll talk to you soon.

Avatar image for Dino Druding

Dino Druding on Feb. 11, 2020

The videos will not play in Chrome?

Avatar image for Dan Bader

Dan Bader RP Team on Feb. 11, 2020

Hi Dino, the video seems to load and play fine for me and I’m also seeing in the server logs that it’s working for others. This might be a browser or connectivity issue on your end. We’ve got this video troubleshooting support article in our support center that should help you get it resolved. If those tips don’t work please send us an email at info@realpython.com and we’ll debug it together :) Best, Dan

Avatar image for Vincent De Haen

Vincent De Haen on Jan. 11, 2021

Hi! Thx for the informative video. I was a bit confused @11:50. You say that str() calls __repr__() internally but doesn’t it call __str__()?

Kr, Vincent

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Jan. 12, 2021

@Vincent De Haen It’s hard to convey the difference between .__str__() and str(), for example, in a video format. However, you can go to the Transcript tab to see the exact words articulated.

The print() function converts its non-keyword arguments to strings with the built-in str() function, which in turn calls the .__str__() method in your custom class. If you don’t define one, then str() fallbacks to calling the .__repr__() method instead:

>>> class Car:
...     def __repr__(self):
...         return 'Calling .__repr__()'
... 
>>> car = Car()
>>> str(car)
'Calling .__repr__()'

You must own this product to join the conversation.