1

I have a class for which I want to be able to print either a short string representation of an object or a longer string representation. Ideally, __str__() would accept a flag that chooses which string to return, and print() would accept that flag as well and use the correct version of __str__() accordingly, but nothing like that seems to exist.

I know that I can include print_short() and print_long() methods inside my class to choose the correct string, but this doesn't seem Pythonic, and violates the Python 3 change by which print() is a function. This would also bypass the use of __str__(), which again, seems unPythonic.

What's the most Pythonic way of handling this? Solutions involving __repr__() won't work, since I'm already using __repr__() as intended, to unambiguously represent the object itself.

5
  • 1
    The most pythonic way I guess, would be to have two methods short_str and long_str. You can use them as @property if you want. Commented Sep 4, 2019 at 14:20
  • 1
    You could add the flag as an attribute of the object of class, and set it before printing. Commented Sep 4, 2019 at 14:21
  • 1
    Whatever you do to determine what flag would be passed to __str__ can be used to choose the appropriate "single-use" function in the first place. Commented Sep 4, 2019 at 14:26
  • 2
    __format__ is probably the method you are looking for. Commented Sep 4, 2019 at 14:27
  • just use 2 attributes for long and short-form ? Commented Sep 4, 2019 at 14:43

1 Answer 1

1

The job of str is to provide "the" string representation of an object, whatever representation you decide is most useful.

If you want to control the formatting of an object, override __format__.

class MyClass:

    def __format__(self, spec):
        ...

If you have code like

s = MyClass()
print("{:r}".format(s))

s.__format__ receives everything after the colon (in this case r) as its spec parameter; it is then entirely up to the definition of __format__ how it uses the spec in deciding what string value to return. You could do something like the following

class MyClass:
    def __format__(self, spec):
        if spec == 's':
            return self._short_str()
        elif spec == 'l':
            return self._long_str()
        else:
            # This includes both no spec whatsoever, which is
            # conventionally expected to behave like __str__
            # and an unrecognized specification, which is just ignored.
            return str(self)

    def _long_str(self):
        return "three"

    def _short_str(self):
        return "3"

    def __str__(self):
        return "III"

>>> x = MyClass()
>>> str(x)
'III'
>>> "{}".format(x)
'III'
>>> "{:whatever}".format(x)
'III'
>>> "{:s}".format(x)
'3'
>>> "{:l}".format(x)
'three'
Sign up to request clarification or add additional context in comments.

2 Comments

That was very helpful, thank you. It does grate on me a bit that, as you said, "The job of str is to provide "the" string representation of an object, whatever representation you decide is most useful.". I understand why there's one repr, but it seems like there could often be many string representations, all of which would be useful in different contexts. But obviously my gripe about that is with Python, not with your answer. Thank you again.
str being a type, one could argue that str(x) never was, nor should have been, the go-to way to produce a string representation of an arbitrary object. Rather, it was convenient that, given an object, str should produce some useful instance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.