Cara menggunakan python __repr__ best practice

How and why to implement Python “to string” conversion in your own classes using Python’s “repr” and “str” mechanisms and associated coding conventions.

When you define a custom class in Python and then try to print one of its instances to the console (or inspect it in an interpreter session), you get a relatively unsatisfying result.

The default “to string” conversion behavior is basic and lacks detail:

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

>>> my_car = Car('red', 37281)
>>> print(my_car)
<__console__.Car object at 0x109b73da0>
>>> my_car
<__console__.Car object at 0x109b73da0>

By default all you get is a string containing the class name and the

>>> print(my_car.color, my_car.mileage)
red 37281
9 of the object instance (which is the object’s memory address in CPython.) That’s better than nothing, but it’s also not very useful.

You might find yourself trying to work around this by printing attributes of the class directly, or even by adding a custom

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

    def __str__(self):
        return f'a {self.color} car'
0 method to your classes:

>>> print(my_car.color, my_car.mileage)
red 37281

The general idea here is the right one—but it ignores the conventions and built-in mechanisms Python uses to handle how objects are represented as strings.

How to Support “To String” Conversion in Your Python Classes?

Instead of building your own class-to-string conversion machinery, modelled after Java’s

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

    def __str__(self):
        return f'a {self.color} car'
1 methods, you’ll be better off adding the
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2 and
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3 “dunder” methods to your class. They are the Pythonic way to control how objects are converted to strings in different situations. You can learn more about this in the .

Let’s take a look at how these methods work in practice. To get started, we’re going to add a

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

    def __str__(self):
        return f'a {self.color} car'
2 method to the
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
5 class we defined earlier:

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

    def __str__(self):
        return f'a {self.color} car'

When you try printing or inspecting a

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

    def __str__(self):
        return f'a {self.color} car'
5 instance now, you’ll get a different, slightly improved result:

>>> my_car = Car('red', 37281)
>>> print(my_car)
'a red car'
>>> my_car
<__console__.Car object at 0x109ca24e0>

Inspecting the car object in the console still gives us the previous result containing the object’s

>>> print(my_car.color, my_car.mileage)
red 37281
9. But printing the object resulted in the string returned by the
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2 method we added.

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

    def __str__(self):
        return f'a {self.color} car'
2 is one of Python’s “dunder” (double-underscore) methods and gets called when you try to convert an object into a string through the various means that are available:

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'

With a proper

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

    def __str__(self):
        return f'a {self.color} car'
2 implementation, you won’t have to worry about printing object attributes directly or writing a separate
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
0 function. It’s the Pythonic way to control string conversion.

By the way, some people refer to Python’s “dunder” methods as “magic methods.” But these methods are not supposed to be magical in any way. The fact that these methods start and end in double underscores is simply a naming convention to flag them as core Python features. It also helps avoid naming collisions with your own methods and attributes. The object constructor

>>> my_car = Car('red', 37281)
>>> print(my_car)
'a red car'
>>> my_car
<__console__.Car object at 0x109ca24e0>
2 follows the same convention, and there’s nothing magical or arcane about it.

Don’t be afraid to use Python’s dunder methods—they’re meant to help you.

Python’s class Car: def __init__(self, color, mileage): self.color = color self.mileage = mileage def __str__(self): return f'a {self.color} car' 3 vs class Car: def __init__(self, color, mileage): self.color = color self.mileage = mileage def __str__(self): return f'a {self.color} car' 2: What Is the Difference Between Them?

Now, our string conversion story doesn’t end there. Did you see how inspecting

>>> my_car = Car('red', 37281)
>>> print(my_car)
'a red car'
>>> my_car
<__console__.Car object at 0x109ca24e0>
5 in an interpreter session still gave that odd
>>> my_car = Car('red', 37281)
>>> print(my_car)
'a red car'
>>> my_car
<__console__.Car object at 0x109ca24e0>
6 result?

This happened because there are actually two dunder methods that control how objects are converted to strings in Python 3. The first one is

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

    def __str__(self):
        return f'a {self.color} car'
2, and you just learned about it. The second one is
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3, and the way it works is similar to
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2, but it is used in different situations. (Python 2.x also has a
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
0 method that I’ll touch on a little later.)

Here’s a simple experiment you can use to get a feel for when

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

    def __str__(self):
        return f'a {self.color} car'
2 or
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3 is used. Let’s redefine our car class so it contains both to-string dunder methods with outputs that are easy to distinguish:

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

    def __repr__(self):
        return '__repr__ for Car'

    def __str__(self):
        return '__str__ for Car'

Now, when you play through the previous examples you can see which method controls the string conversion result in each case:

>>> my_car = Car('red', 37281)
>>> print(my_car)
__str__ for Car
>>> '{}'.format(my_car)
'__str__ for Car'
>>> my_car
__repr__ for Car

This experiment confirms that inspecting an object in a Python interpreter session simply prints the result of the object’s

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

    def __str__(self):
        return f'a {self.color} car'
3.

Interestingly, containers like lists and dicts always use the result of

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

    def __str__(self):
        return f'a {self.color} car'
3 to represent the objects they contain. Even if you call
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
5 on the container itself:

str([my_car])
'[__repr__ for Car]'

To manually choose between both string conversion methods, for example, to express your code’s intent more clearly, it’s best to use the built-in

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
6 and
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
7 functions. Using them is preferable over calling the object’s
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2 or
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3 directly, as it looks nicer and gives the same result:

>>> str(my_car)
'__str__ for Car'
>>> repr(my_car)
'__repr__ for Car'

Even with this investigation complete, you might be wondering what the “real-world” difference is between

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

    def __str__(self):
        return f'a {self.color} car'
2 and
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3. They both seem to serve the same purpose, so it might be unclear when to use each.

With questions like that, it’s usually a good idea to look into what the Python standard library does. Time to devise another experiment. We’ll create a

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

    def __repr__(self):
        return '__repr__ for Car'

    def __str__(self):
        return '__str__ for Car'
2 object and find out how it uses
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3 and
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2 to control string conversion:

>>> import datetime
>>> today = datetime.date.today()

The result of the date object’s

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

    def __str__(self):
        return f'a {self.color} car'
2 function should primarily be readable.

It’s meant to return a concise textual representation for human consumption—something you’d feel comfortable displaying to a user. Therefore, we get something that looks like an ISO date format when we call

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
6 on the date object:

>>> print(my_car.color, my_car.mileage)
red 37281
0

With

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

    def __str__(self):
        return f'a {self.color} car'
3, the idea is that its result should be, above all, unambiguous.

The resulting string is intended more as a debugging aid for developers. And for that it needs to be as explicit as possible about what this object is. That’s why you’ll get a more elaborate result calling

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
7 on the object. It even includes the full module and class name:

>>> print(my_car.color, my_car.mileage)
red 37281
1

We could copy and paste the string returned by

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

    def __str__(self):
        return f'a {self.color} car'
3 and execute it as valid Python to recreate the original date object. This is a neat approach and a good goal to keep in mind while writing your own reprs.

On the other hand, I find that it is quite difficult to put into practice. Usually it won’t be worth the trouble and it’ll just create extra work for you. My rule of thumb is to make my

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

    def __str__(self):
        return f'a {self.color} car'
3 strings unambiguous and helpful for developers, but I don’t expect them to be able to restore an object’s complete state.

Why Every Python Class Needs a class Car: def __init__(self, color, mileage): self.color = color self.mileage = mileage def __str__(self): return f'a {self.color} car' 3

If you don’t add a

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

    def __str__(self):
        return f'a {self.color} car'
2 method, Python falls back on the result of
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3 when looking for
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2. Therefore, I recommend that you always add at least a
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3 method to your classes. This will guarantee a useful string conversion result in almost all cases, with a minimum of implementation work.

Here’s how to add basic string conversion support to your classes quickly and efficiently. For our

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

    def __str__(self):
        return f'a {self.color} car'
5 class we might start with the following
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3:

>>> print(my_car.color, my_car.mileage)
red 37281
2

Please note that I’m using the

>>> my_car = Car('red', 37281)
>>> print(my_car)
__str__ for Car
>>> '{}'.format(my_car)
'__str__ for Car'
>>> my_car
__repr__ for Car
8 conversion flag to make sure the output string uses
>>> my_car = Car('red', 37281)
>>> print(my_car)
__str__ for Car
>>> '{}'.format(my_car)
'__str__ for Car'
>>> my_car
__repr__ for Car
9 and
str([my_car])
'[__repr__ for Car]'
0 instead of
str([my_car])
'[__repr__ for Car]'
1 and
str([my_car])
'[__repr__ for Car]'
2.

This works nicely, but one downside is that we’ve repeated the class name inside the format string. A trick you can use here to avoid this repetition is to use the object’s

str([my_car])
'[__repr__ for Car]'
3 attribute, which will always reflect the class’ name as a string.

The benefit is you won’t have to modify the

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

    def __str__(self):
        return f'a {self.color} car'
3 implementation when the class name changes. This makes it easy to adhere to the Don’t Repeat Yourself (DRY) principle:

>>> print(my_car.color, my_car.mileage)
red 37281
3

The downside of this implementation is that the format string is quite long and unwieldy. But with careful formatting, you can keep the code nice and PEP 8 compliant.

With the above

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

    def __str__(self):
        return f'a {self.color} car'
3 implementation, we get a useful result when we inspect the object or call
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
7 on it directly:

>>> print(my_car.color, my_car.mileage)
red 37281
4

Printing the object or calling

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
6 on it returns the same string because the default
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2 implementation simply calls
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
3:

>>> print(my_car.color, my_car.mileage)
red 37281
5

I believe this approach provides the most value with a modest amount of implementation work. It’s also a fairly cookie-cutter approach that can be applied without much deliberation. For this reason, I always try to add a basic

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

    def __str__(self):
        return f'a {self.color} car'
3 implementation to my classes.

Here’s a complete example for Python 3, including an optional

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

    def __str__(self):
        return f'a {self.color} car'
2 implementation:

>>> print(my_car.color, my_car.mileage)
red 37281
6

Python 2.x Differences: >>> print(my_car) a red car >>> str(my_car) 'a red car' >>> '{}'.format(my_car) 'a red car' 0

In Python 3 there’s one data type to represent text across the board:

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
5. It holds unicode characters and can represent most of the world’s writing systems.

Python 2.x uses a different data model for strings. There are two types to represent text:

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
5, which is limited to the ASCII character set, and
>>> str(my_car)
'__str__ for Car'
>>> repr(my_car)
'__repr__ for Car'
5, which is equivalent to Python 3’s
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
5.

Due to this difference, there’s yet another dunder method in the mix for controlling string conversion in Python 2:

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
0. In Python 2,
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2 returns bytes, whereas
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
0 returns characters.

For most intents and purposes,

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
0 is the newer and preferred method to control string conversion. There’s also a built-in
>>> import datetime
>>> today = datetime.date.today()
1 function to go along with it. It calls the respective dunder method, similar to how
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
6 and
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
7 work.

So far so good. Now, it gets a little more quirky when you look at the rules for when

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

    def __str__(self):
        return f'a {self.color} car'
2 and
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
0 are called in Python 2:

The

>>> import datetime
>>> today = datetime.date.today()
6 statement and
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
6 call
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2. The
>>> import datetime
>>> today = datetime.date.today()
1 built-in calls
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
0 if it exists, and otherwise falls back to
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2 and decodes the result with the system text encoding.

Compared to Python 3, these special cases complicate the text conversion rules somewhat. But there is a way to simplify things again for practical purposes. Unicode is the preferred and future-proof way of handling text in your Python programs.

So generally, what I would recommend you do in Python 2.x is to put all of your string formatting code inside the

>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
0 method and then create a stub
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2 implementation that returns the unicode representation encoded as UTF-8:

>>> print(my_car.color, my_car.mileage)
red 37281
7

The

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

    def __str__(self):
        return f'a {self.color} car'
2 stub will be the same for most classes you write, so you can just copy and paste it around as needed (or put it into a base class where it makes sense). All of your string conversion code that is meant for non-developer use then lives in
>>> print(my_car)
a red car
>>> str(my_car)
'a red car'
>>> '{}'.format(my_car)
'a red car'
0.

Here’s a complete example for Python 2.x:

>>> print(my_car.color, my_car.mileage)
red 37281
8

When to use class Car: def __init__(self, color, mileage): self.color = color self.mileage = mileage def __str__(self): return f'a {self.color} car' 2 vs class Car: def __init__(self, color, mileage): self.color = color self.mileage = mileage def __str__(self): return f'a {self.color} car' 3 in Python:

  • You can control to-string conversion in your own classes using the
    class Car:
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __str__(self):
            return f'a {self.color} car'
    
    2 and
    class Car:
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __str__(self):
            return f'a {self.color} car'
    
    3 “dunder” methods. Writing your own Java-esque “tostring” methods is considered unpythonic.
  • The result of the
    class Car:
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __str__(self):
            return f'a {self.color} car'
    
    2 method should be readable. The result of
    class Car:
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __str__(self):
            return f'a {self.color} car'
    
    3 should be unambiguous.
  • You should always add a
    class Car:
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __str__(self):
            return f'a {self.color} car'
    
    3 to your classes. The default implementation for
    class Car:
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __str__(self):
            return f'a {self.color} car'
    
    2 just calls
    class Car:
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __str__(self):
            return f'a {self.color} car'
    
    3 internally, so by implementing
    >>> print(my_car.color, my_car.mileage)
    red 37281
    
    15 support you’ll get the biggest benefit.
  • On Python 2.x you’ll want to use
    >>> print(my_car)
    a red car
    >>> str(my_car)
    'a red car'
    >>> '{}'.format(my_car)
    'a red car'
    
    0 instead of
    class Car:
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __str__(self):
            return f'a {self.color} car'
    
    2.

If you’d like to dig deeper into the subject, be sure to watch my related YouTube tutorial on when to use

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

    def __str__(self):
        return f'a {self.color} car'
3 vs
class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def __str__(self):
        return f'a {self.color} car'
2. It’s also embedded at the top of the article. Happy Pythoning!

Object-Oriented Programming in Python: The 7 Best Resources (A Free PDF Cheat Sheet)

There are so many ways to learn about Object-Oriented Programming with Python. But only a few of them are actually useful. This (totally free) cheat sheet will point you to the tutorials, videos, and books I found the most valuable to learn more about OOP with Python.