repr()

The built-in function repr() returns the "official" printable representation of an object. It's primarily meant for debugging, so the output should be information-rich and unambiguous.

For example, the default implementation returns the instance's location in memory:

class Thing:
    def __init__(self, a: str, b: int):
        self.a = a
        self.b = b

thing = Thing("dummy", 8)

repr(thing)  # '<__main__.Thing object at 0x7f62db791970>'

Even better, many libraries implement repr() to produce a valid Python expression that would yield an instance with the same attributes if passed to eval(). Here's an example using dataclass:

from dataclasses import dataclass

@dataclass
class BetterThing:
    a: str
    b: int

better_thing = BetterThing("dummy", 8)

repr(better_thing)  # "BetterThing(a='dummy', b=8)"

# A similar instance can be created from the repr!
eval(repr(better_thing))  # BetterThing(a='dummy', b=8)

And if these implementations aren't sufficient, you can always return custom values for repr() by overriding the special method __repr__() with your own implementation:

class SomeThing:
    def __init__(self, a: str, b: int):
        self.a = a
        self.b = b

    def __repr__(self):
        return f"<SomeThing(a="{self.a}", b={self.b})>"

some_thing = SomeThing("dummy", 8)

repr(some_thing)  # '<SomeThing(a="dummy", b=8)>'

It's recommended that these custom implementations either return a valid Python expression or a string within angular brackets, as done in the example above.

str()

On the other hand, str() is the "informal" printable representation of an object. It's used by print() and the logging module, and its primary goal is readability rather than unambiguity.

By default, the implementation calls __repr__():

class Thing:
    def __init__(self, a: str, b: int):
        self.a = a
        self.b = b

thing = Thing("dummy", 8)

str(thing)  # '<__main__.Thing object at 0x7f62db791970>'

And similar to __repr__ for repr(), you can customize str() by implementing your own __str__():

class SomeThing:
    def __init__(self, a: str, b: int):
        self.a = a
        self.b = b

    def __str__(self):
        return f"<SomeThing(self.a)>"

some_thing = SomeThing("dummy", 8)

str(some_thing)  # '<SomeThing(dummy)>'

However, unlike __repr__, there aren't any expectations about the string format that should be returned by __str__.

Do they ever differ?

In practice, repr() and str() rarely differ, and most developers implement __repr__() with the expectation that both repr() and str() will use it. However, sometimes the formal representation of repr() isn't readable and it makes sense to use another representation in those cases. This is common when working with dates or times:

from datetime import datetime

now = datetime(2021, 3, 5, 1, 2, 34, 567890)
repr(now)  # 'datetime.datetime(2021, 3, 5, 1, 2, 34, 567890)'
str(now)   # '2021-03-05 01:02:34.567890'

In this case, repr() outputs a valid Python expression while str() outputs a human-readable string.

Personally, I find it somewhat silly to have a distinction between the two. Many people don't recognize the difference, so they're rarely implemented differently. And since I typically use logging for debugging later, it seems strange to me that the logging module uses str() instead of repr(). Plus, doesn't the distinction just make it harder to follow one of the Zen of Python maxims (There should be one – and preferably only one – obvious way to do it.)?

Personal opinions aside, knowing the difference between repr() and str() can help you keep your code simple and readable.

Trivia Night | George Fox University | Newberg, Oregon

It's a fun bit of Python trivia too!