Categories
magic-methods python repr

What is the difference between __str__ and __repr__?

3430

What is the difference between __str__ and __repr__ in Python?

0

    3267

    +100

    Alex summarized well but, surprisingly, was too succinct.

    First, let me reiterate the main points in Alex’s post:

    • The default implementation is useless (it’s hard to think of one which wouldn’t be, but yeah)
    • __repr__ goal is to be unambiguous
    • __str__ goal is to be readable
    • Container’s __str__ uses contained objects’ __repr__

    Default implementation is useless

    This is mostly a surprise because Python’s defaults tend to be fairly useful. However, in this case, having a default for __repr__ which would act like:

    return "%s(%r)" % (self.__class__, self.__dict__)
    

    would have been too dangerous (for example, too easy to get into infinite recursion if objects reference each other). So Python cops out. Note that there is one default which is true: if __repr__ is defined, and __str__ is not, the object will behave as though __str__=__repr__.

    This means, in simple terms: almost every object you implement should have a functional __repr__ that’s usable for understanding the object. Implementing __str__ is optional: do that if you need a “pretty print” functionality (for example, used by a report generator).

    The goal of __repr__ is to be unambiguous

    Let me come right out and say it — I do not believe in debuggers. I don’t really know how to use any debugger, and have never used one seriously. Furthermore, I believe that the big fault in debuggers is their basic nature — most failures I debug happened a long long time ago, in a galaxy far far away. This means that I do believe, with religious fervor, in logging. Logging is the lifeblood of any decent fire-and-forget server system. Python makes it easy to log: with maybe some project specific wrappers, all you need is a

    log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)
    

    But you have to do the last step — make sure every object you implement has a useful repr, so code like that can just work. This is why the “eval” thing comes up: if you have enough information so eval(repr(c))==c, that means you know everything there is to know about c. If that’s easy enough, at least in a fuzzy way, do it. If not, make sure you have enough information about c anyway. I usually use an eval-like format: "MyClass(this=%r,that=%r)" % (self.this,self.that). It does not mean that you can actually construct MyClass, or that those are the right constructor arguments — but it is a useful form to express “this is everything you need to know about this instance”.

    Note: I used %r above, not %s. You always want to use repr() [or %r formatting character, equivalently] inside __repr__ implementation, or you’re defeating the goal of repr. You want to be able to differentiate MyClass(3) and MyClass("3").

    The goal of __str__ is to be readable

    Specifically, it is not intended to be unambiguous — notice that str(3)==str("3"). Likewise, if you implement an IP abstraction, having the str of it look like 192.168.1.1 is just fine. When implementing a date/time abstraction, the str can be “2010/4/12 15:35:22”, etc. The goal is to represent it in a way that a user, not a programmer, would want to read it. Chop off useless digits, pretend to be some other class — as long is it supports readability, it is an improvement.

    Container’s __str__ uses contained objects’ __repr__

    This seems surprising, doesn’t it? It is a little, but how readable would it be if it used their __str__?

    [moshe is, 3, hello
    world, this is a list, oh I don't know, containing just 4 elements]
    

    Not very. Specifically, the strings in a container would find it way too easy to disturb its string representation. In the face of ambiguity, remember, Python resists the temptation to guess. If you want the above behavior when you’re printing a list, just

    print("[" + ", ".join(l) + "]")
    

    (you can probably also figure out what to do about dictionaries.

    Summary

    Implement __repr__ for any class you implement. This should be second nature. Implement __str__ if you think it would be useful to have a string version which errs on the side of readability.

    12

    • 315

      Definitely disagree with your opinion that debugging isn’t the way to go. For development use a debugger (and/or logging), for production use logging. With a debugger you have a view of everything that went wrong when the problem occurred. You can see the full picture. Unless you are logging EVERYTHING you can’t get that. Plus if you are logging everything you’re going have to wade through tons of data to get at what you want.

      – Samuel

      Feb 21, 2015 at 19:06

    • 34

      Great answer (except the bit about not using debuggers). I’d just like to add a link to this other Q&A about str vs unicode in Python 3 which could be relevant to the discussion for people who have made the switch.

      Mar 23, 2015 at 21:04


    • 3

      I heard that a variable l (lowercase letter “L”) will be syntax error in python 4.0 😉

      – hans

      Jul 10, 2019 at 15:54

    • 20

      on debugger vs no debugger: don’t get such entrenched opinions. In some applications debugging is not realistic, typically when real-time is involved, or when your code only executes remotely on a platform with little access or no console. In most other cases it will be much quicker to stop at an exception to investigate, or to set a breakpoint, because you don’t have to go through thousands of lines of logging (which will clutter your disk and slow down the application). Finally, it’s not always possible to log, for example on embedded devices, there debugger is your friend too.

      – RedGlyph

      Aug 2, 2019 at 11:42

    • 2

      About debuggging vs logging, they are both useful. If a bug is reproducible, debugging is more simple. If the bug is randomic, logging is essential.

      Jan 15, 2020 at 15:16

    727

    My rule of thumb: __repr__ is for developers, __str__ is for customers.

    6

    • 15

      This is true because for obj = uuid.uuid1(), obj.__str__() is “2d7fc7f0-7706-11e9-94ae-0242ac110002” and obj.__repr__() is “UUID(‘2d7fc7f0-7706-11e9-94ae-0242ac110002’)”. Developers need (value + origin) whereas customers need a value and they don’t care how they got it!

      May 15, 2019 at 11:45


    • 10

      Here customer may not necessarily mean end-user. It’s the client or user of the object. So if its an SDK then the SDK developers will use __str__ so normal developers have readable object. On the other hand, __repr__ is for the SDK developers themselves.

      Jan 9, 2020 at 13:16

    • @NarenYellavula if you’re exposing a UUID to a customer you’re probably doing something wrong.

      Dec 18, 2021 at 19:37

    • @MarkRansom why is that?

      Apr 13 at 9:01

    • @AbdessabourMtk they’re overly complex, and there’s no protection against typing them wrong. Maybe in certain contexts like as part of a QR code they would be OK.

      Apr 13 at 14:02

    483

    Unless you specifically act to ensure otherwise, most classes don’t have helpful results for either:

    >>> class Sic(object): pass
    ... 
    >>> print(str(Sic()))
    <__main__.Sic object at 0x8b7d0>
    >>> print(repr(Sic()))
    <__main__.Sic object at 0x8b7d0>
    >>> 
    

    As you see — no difference, and no info beyond the class and object’s id. If you only override one of the two…:

    >>> class Sic(object): 
    ...   def __repr__(self): return 'foo'
    ... 
    >>> print(str(Sic()))
    foo
    >>> print(repr(Sic()))
    foo
    >>> class Sic(object):
    ...   def __str__(self): return 'foo'
    ... 
    >>> print(str(Sic()))
    foo
    >>> print(repr(Sic()))
    <__main__.Sic object at 0x2617f0>
    >>> 
    

    as you see, if you override __repr__, that’s ALSO used for __str__, but not vice versa.

    Other crucial tidbits to know: __str__ on a built-on container uses the __repr__, NOT the __str__, for the items it contains. And, despite the words on the subject found in typical docs, hardly anybody bothers making the __repr__ of objects be a string that eval may use to build an equal object (it’s just too hard, AND not knowing how the relevant module was actually imported makes it actually flat out impossible).

    So, my advice: focus on making __str__ reasonably human-readable, and __repr__ as unambiguous as you possibly can, even if that interferes with the fuzzy unattainable goal of making __repr__‘s returned value acceptable as input to __eval__!

    6

    • 44

      In my unit tests I always check that eval(repr(foo)) evaluates to an object equal to foo. You’re right that it won’t work outside of my test cases since I don’t know how the module is imported, but this at least ensures that it works in some predictable context. I think this a good way of evaluating if the result of __repr__ is explicit enough. Doing this in a unit test also helps ensure that __repr__ follows changes to the class.

      Nov 15, 2011 at 19:58

    • 5

      I always try to make sure that either eval(repr(spam)) == spam (at least in the right context), or eval(repr(spam)) raises a SyntaxError. That way you avoid confusion. (And that’s almost true for the builtins and most of the stdlib, except for, e.g., recursive lists, where a=[]; a.append(a); print(eval(repr(a))) gives you [[Ellipses]]…) Of course I don’t do that to actually use eval(repr(spam)), except as a sanity check in unit tests… but I do sometimes copy and paste repr(spam) into an interactive session.

      – abarnert

      Sep 20, 2014 at 5:34


    • Why would not containers (lists, tuples) use __str__ for each element instead of __repr__? Seems plain wrong to me, as I implemented a readable __str__ in my object and when it is part of a list I see the uglier __repr__ instead.

      – SuperGeo

      Jan 26, 2018 at 14:15

    • Just ran into an annoying bug related to the fact that eval(repr(x)) fails even for builtin types: class A(str, Enum): X = 'x' will raise SyntaxError on eval(repr(A.X)). It’s sad, but understandable. BTW, eval(str(A.X)) actually works, but of course only if class A is in scope — so it’s probably not very useful.

      – max

      Jan 13, 2019 at 13:26


    • 1

      @abarnert: for a custom class Spam, eval(repr(spam)) == spam would require Spam.__eq__to be implemented as well, right? By default object.__eq__ uses is (docs).

      – djvg

      Dec 4, 2020 at 10:32