Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does adding formatting information to a f-string with tuple values raise a TypeError?

I'm trying to understand the following behavior of f-strings in Python:

The following line in which the tuple value is converted explicitly via str() works fine.

f"{str((1,2,3)):>10}"

However if I drop the explicit conversion the line raises a TypeError: unsupported format string passed to tuple.__format__:

f"{(1,2,3):>20}"

There are no issues when there isn't any formatting given:

f"{(1,2,3)}"

I had expected that the f-string converts the tuple into a string automagically and then enforces the formatting requirements. This does not seem to be the case. Can somebody explain? Is there another workaround other then the explicit conversion via str()?

like image 850
Ben Bkhdt Avatar asked Nov 20 '25 00:11

Ben Bkhdt


2 Answers

As you experienced, there is some magic going on. However, it is not that every item is just being converted to string before formatting.

The TypeError explains what Python is trying to do: It is trying to call the __format__ method of your tuple. But it fails because tuple.__format__ does not expect a > argument. If you were to fine-tune the formatting of your own class, you could do something like this:

class MyType:
    def __init__(self, value):
        self.value = value

    def __format__(self, format_spec):
        return f"this is the value {self.value} formatted against {format_spec}"


if __name__ == '__main__':
    d = MyType(6)

    print(f"{d:>10}")

Output:

this is the value 6 formatted against >10

So it would be up to your own MyType.__format__ to generate and return a string according to the format_spec.

One native Python type that has a __format__ method that deals with a format_spec like >10 would be the string class. That is the reason f"{str((1,2,3)):>10}" works.

What you could do instead would be to use the ! marker to convert the tuple to string - this is equivalent to using str() but less verbose:

f"{(1,2,3)!s:>10}"

Output: ' (1, 2, 3)'

With one space added to the left as wanted.

like image 139
Lydia van Dyke Avatar answered Nov 21 '25 14:11

Lydia van Dyke


You can do it by explicitly specifying the conversion to a string in the format portion of the string with a literal !s like this:

f"{(1,2,3)!s:>10}'

This is needed because the width specification :>10 only applies to strings.

like image 24
martineau Avatar answered Nov 21 '25 14:11

martineau



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!