[Python-Dev] Subtle difference between f-strings and str.format()

Tim Peters tim.peters at gmail.com
Wed Mar 28 19:48:40 EDT 2018


[Tim Delaney <timothy.c.delaney at gmail.com>]
> ...
> If I'm not mistaken, #3 would result in the optimiser changing str.format()
> into an f-string in-place. Is this correct? We're not talking here about
> people manually changing the code from str.format() to f-strings, right?

All correct.  It's a magical transformation from one spelling to another.


> I would argue that any optimisation needs to have the same semantics as the
> original code - in this case, that all arguments are evaluated before the
> string is formatted.

That's why Serhiy is asking about it - there _are_ potentially visible
changes in behavior under all but one of his suggestions.


> I also assumed (not having actually used an f-string) that all its
> formatting arguments were evaluated before formatting.

It's a string - it doesn't have "arguments" as such.  For example:

def f(a, b, n):
    return f"{a+b:0{n}b}"  # the leading "f" makes it an f-string

Then

>>> f(2, 3, 12)
'000000000101'

The generated code currently interleaves evaluating expressions with
formatting the results in a more-than-less obvious way, waiting until
the end to paste all the formatted fragments together.  As shown in
the example, this can be more than one level deep (the example needs
to paste together "0", str(n), and "b" to _build_ the format code for
`a+b`).


> So my preference would be (if my understanding in the first line is
> correct):
>
> 1: +0

That's the only suggestion with no potentially visible changes.  I'll
add another:  leave `.format()` alone entirely - there's no _need_ to
"optimize" it, it's just a maybe-nice-to-have.


> 2a: +0.5
> 2b: +1

Those two don't change the behaviors of `.format()`, but _do_ change
some end-case behaviors of f-strings.  If you're overly ;-) concerned
about the former, it would be consistent to be overly concerned about
the latter too.


> 3: -1

And that's the one that proposes to let .format() also interleave
expression evaluation (but still strictly "left to right") with
formatting.

If it were a general code transformation, I'm sure everyone would be
-1.  As is, it's  hard to care.  String formatting is a tiny area, and
format methods are generally purely functional (no side effects).  If
anyone has a non-contrived example where the change would make a lick
of real difference, they shouldn't be shy about posting it :-)  I
looked, and can't find any in my code.


More information about the Python-Dev mailing list