2

Can __str__ return literally anything my soul desires?

The documentation on __str__ states:

[...] the “informal” or nicely printable string representation of an object

How should one interpret it?

  • A. That it can return anything as long as in my opinion it represents the object.
  • B. That it should return unambiguous representation of the object, albeit it can be formatted in any way I please.

Example of A:

class Vehicle:
    def __init__(self, owner):
        self.owner = owner
        self.wheels = 4
    def __str__(self):
        return "%s with %s wheels" % (self.owner, self.wheels)
print(Vehicle('Benjamin'))
>>> Benjamin with 4 wheels

Example of B:

class Vehicle:
    def __init__(self, owner):
        self.owner = owner
        self.wheels = 4
    def __str__(self):
        return "Vehicle, owner is %s, with %s wheels" % (self.owner, self.wheels)
print(Vehicle('Benjamin'))
>>> Vehicle, owner is Benjamin, with 4 wheels

Just about all resources I find (1, 2, 3, 4, 5, 6) suggest that the output - while it can be informal - should be unambiguous and explicit (and it makes sense: Explicit is better than implicit., Readability counts. In the face of ambiguity, refuse the temptation to guess.).

However there are a few that suggest that one could in fact be ambiguous and implicit (1, 2) given the 'informal' word in the documentation. I found one fellow developer who states that one can use absolutely any representation of the object in __str__, and that __repr__ is for unambiguous and explicit representations. I'd like to understand their perspective but can't find any reasoning supporting their case. Can you suggest how one should interpret that documentation and support your reasoning?

Voy
  • 5,286
  • 1
  • 49
  • 59
  • 2
    `__repr__` should return a valid literal that can be used to re-construct the exact same object. `__str__` can be anything you want, but obviously should preferably have something to do with your object. You shouldn’t confuse `__str__` with a separate template for more complex formatting; there are probably many different situations in which you want to use your object, so hard coding one sort of template in its `__str__` method is not too useful. – deceze Jan 12 '21 at 05:46
  • Thanks for the answer! Could you provide some sources or expand on your logic behind saying "`__str__` can be anything you want"? The docs don't seem to state such - quite the opposite, that it should be a representation of the object (not that it 'should preferably have something to do with it') - which is why I'm wondering how come one would say it could be 'anything you want' – Voy Jan 12 '21 at 05:56
  • 2
    The documentation is pretty clear that `__str__` can return anything you deem fit (as long as it is a string). Note, even the documentation for `__repr__` which is supposd to be the "stricter" version isn't super strict, it states things like "if at all possible". Don't overthink this. – juanpa.arrivillaga Jan 12 '21 at 06:30
  • Thanks for your thoughts Juanpa and for the encouragement to not overthink this, but the documentation states quite the oposite, doesn't it? 'representation of an object' is not exactly 'anything you deem fit'. Looking at the definition of verb 'to represent' clarifies that not everything will do, but that the returned string needs to fit a particular assumption. If I returned 'MyObject' from `Vehicle.__str__`, would that be a correct implementation? – Voy Jan 12 '21 at 06:46

1 Answers1

2

The question is how these things are used. As an example of how __str__ can be used, look at Django's admin interface. Simply by registering one of your model classes, it generates a full featured admin interface around it. By default, in a list of such model objects, the objects are represented using their __str__ representation (this can be customised further, but this is the sensible default). So, the __str__ should return a representation that makes sense in an admin interface. It shouldn't be too verbose, it shouldn't be a sentence, but it should uniquely identify the object.

So how to uniquely identify the object in a useful way depends on what it is exactly and your app. Let's say you have a blog app, then for identifying each article in it, something like this might be most useful:

def __str__(self):
    return f'{self.id} — {self.title}'

It's really up to you and your use case, but mostly it should be something useful for a human. There's no programatic use for __str__ representations, so Python doesn't particularly care nor dictate any specific format it must adhere to.

__repr__ should, if at all possible, return a literal which allows you to reconstruct the exact object. This is mostly for the developer, and can greatly aid debugging. If you do something like print(things) and get this:

[<__main__.Thing object at 0x818745692312>]

That only gives you minimal information and not much more. If you customise __repr__:

def __repr__(self):
    return f'{type(self).__name__}(foo={self.foo!r})'

…and your list now prints like this:

[Thing(foo='bar')]

Now you can copy-paste this directly into a Python shell and play around with it further to reproduce a problem and debug it further. That's what it's for, and using it properly can simplify your development.

deceze
  • 510,633
  • 85
  • 743
  • 889