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

A Complete Example & Best Practices

Learn why you should at least have a .__repr__() method in your classes. This lesson will show you how to adhere to the Don’t Repeat Yourself (DRY) principle when working with .__repr__() by taking advantage of __class__.__name__:

Python
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __repr__(self):
        return '{self.__class__.__name__}({self.color}, {self.mileage})'.format(self=self)

00:00 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,

00:52 and self.mileage, right? And then, 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.

01:16 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.

01:31 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?

01:41 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__().

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

01:59 And also, when I call str() on it or when I print the Car,

02:04 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.

02:17 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.

Avatar image for Pygator

Pygator on Aug. 29, 2019

This is great python knowledge. But what’s the point of the previous distinction? This is both human readable and unambigous.

Avatar image for justpeter25x

justpeter25x on Nov. 16, 2019

can you please explain on this more:{self.class.name} For what you do that?

Avatar image for justpeter25x

justpeter25x on Nov. 16, 2019

can you please explain here in this statement: return ‘{self.class.name}({self.color}, {self.mileage})’.format(self=self)

How i can return the statement in this way: return (‘{self.class.name} , {}, {} car’.format(self.color,self.mileage)) Is it possible?I try but i got the key error ‘self’

Avatar image for Learn2Improve

Learn2Improve on Dec. 4, 2019

@Pygator - if you are refering to difference between this and previous lesson - it is mentioned that it is best practice to at least have __repr__ method. If you don’t have a __str__ method and still call it - it will fallback to __repr__ method, so you have covered both cases (str(object) and repr(object)) via just __repr__ method.

If you do need to have __str__ method on top of __repr__ e.g. for more user friendly output - that is still possible and entirely dependent on your choice.

In code above if you add following at the end of the script (not indented):

car1 = Car("Red", 10000)
print(repr(car1))
print(str(car1))

When you execute the code you get following result:

Car(Red, 10000)
Car(Red, 10000)

As you can see both methods return same result because __str__ is not defined, hence it falls back to __repr__ method. If you do define __str__ method you would get different result. Here is example of adding __str__ to code from Dan (I have made changes by using f-string instead of .format):

class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __repr__(self):
        return f'{self.__class__.__name__}({self.color}, {self.mileage})'

    def __str__(self):
        return f'My car color is: {self.color} and its mileage is: {self.mileage}!'


car1 = Car("Red", 10000)
print(repr(car1))
print(str(car1))

And result when you run this script is:

Car(Red, 10000)
My car color is: Red and its mileage is: 10000!

So, since both were defined, __str__ and __repr__ methods were called. And while first result gives exact code that was needed to create object (which would be useful for developer), second result (__str__ method) returns something that would be more understandable to end user who doesn’t really care what code is needed to create an object.

Hope it helps

L2I

Avatar image for Learn2Improve

Learn2Improve on Dec. 5, 2019

@justpeter25x

Regarding your question: can you please explain here in this statement: return '{self.__class__.__name__}({self.color}, {self.mileage})'.format(self=self)

Please note that in Dan’s code under .format() self is defined (self=self). This is because previous self occurences in {} inside quoatation marks are not automatically recognized as self object, they are only defined within .format(self=self) part of statement.

This is how string mehtod .format() works. You cannot put variables directly in curly brackets with this method.

So, your code: return ‘{self.__class__.__name__} , {}, {} car’.format(self.color,self.mileage) when it is read by Python does not know what self in {self.__class__.__name__} is, and returns KeyError.

You do have alternative for your code to work by using f-strings (Python 3.6 and later). Since f-string allows you to call variables directly in {}, your statement would work if written like this: return f'{self.__class__.__name__}, {self.color}, {self.mileage} car'

For example, in this case if you run this script and then in console put:

car1 = Car("Red", 10000)
print(repr(car1))

Your result would be:

Car, Red, 10000 car

I am not sure if this is what you wanted to be shown, but you can work on your code from there.

Take care,

L2I

Avatar image for agerbes

agerbes on Jan. 19, 2020

I tried to run the example. I wrote the class in a python script and ran it on the console. Unfortunately for me it doesn’t work as shown in the video. Just the print statement gives me an output, but not my_car or str(my_car).

Avatar image for Dan Bader

Dan Bader RP Team on Jan. 20, 2020

@agerbes: If you can post a code example that’ll make it easier to figure out what’s happening. You can post it here or on Slack (#coding-questions) so we can look into it :)

Become a Member to join the conversation.