f-string representation different than str()

Question:

I had always thought that f-strings invoked the __str__ method. That is, f'{x}' was always the same as str(x). However, with this class

class Thing(enum.IntEnum):
    A = 0

f'{Thing.A}' is '0' while str(Thing.A) is 'Thing.A'. This example doesn’t work if I use enum.Enum as the base class.

What functionality do f-strings invoke?

Asked By: Daniel Walker

||

Answers:

From "Formatted string literals" in the Python reference:
f-strings are invoke the "format protocol", same as the format built-in function. It means that the __format__ magic method is called instead of __str__.

class Foo:
    def __repr__(self):
        return "Foo()"

    def __str__(self):
        return "A wild Foo"
    
    def __format__(self, format_spec):
        if not format_spec:
            return "A formatted Foo"
        return f"A formatted Foo, but also {format_spec}!"

>>> foo = Foo()
>>> repr(foo)
'Foo()'
>>> str(foo)
'A wild Foo'
>>> format(foo)
'A formatted Foo'
>>> f"{foo}"
'A formatted Foo'
>>> format(foo, "Bar")
'A formatted Foo, but also Bar!'
>>> f"{foo:Bar}"
'A formatted Foo, but also Bar!'

If you don’t want __format__ to be called, you can specify !s (for str), !r (for repr) or !a (for ascii) after the expression:

>>> foo = Foo()
>>> f"{foo}"
'A formatted Foo'
>>> f"{foo!s}"
'A wild Foo'
>>> f"{foo!r}"
'Foo()'

This is occasionally useful with strings:

>>> key = 'somethingn nasty!'
>>> error_message = f"Key not found: {key!r}"
>>> error_message
"Key not found: 'something\n nasty!'"
Answered By: decorator-factory

f-strings in Python don’t use __str__ or __repr__. They use __format__.
So to get the same result as f'{Thing.A}', you’d need to call format(Thing.A).

The __format__(...) method allows you to add more formatting features (for example with floats you can do {:.2f} to round the number to two decimals).

If format() hasn’t been defined for a class/object, python will fall back to __str__. That’s why most people think str() is the method used in f-strings.

The docs cover the options you have with __format__ in detail: Link to Documentation

Answered By: Tim Woocker
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.