Is it ok to mix normal string and new f-string like this:
import timeit
format = """
def format(name, age):
return (
f'He said his name is '
f'{name} and he is '
f'{age} years old.'
)
""", """
def format(name, age):
return (
'He said his name is '
f'{name} and he is '
f'{age} years old.'
)
"""
test = """
def test():
for name in ('Fred', 'Barney', 'Gary', 'Rock', 'Perry', 'Jackie'):
for age in range (20, 200):
format(name, age)
"""
for fmt in format:
print(timeit.timeit('test()', fmt + test, number=10000))
[out]:
3.4188902939995387
3.3931472289996236
Is this ok to use or it is not considered best practice to mix normal string and f-string?
The opinion-free question here is what does it mean to “compile-time concatenate” formatted string “literals” that are really runtime expressions? The language reference merely says that you can.
Experimentation with dis
reveals that even a lone f-string is decomposed into interstitial string literals and formatting expressions (which are compiled to the new FORMAT_VALUE
opcode, not turned into calls to str.format
or so). Each f-string is handled this way separately (prior to concatenation, so f"{x" f"}"
is invalid). The prefix and suffix string literals, if any, that result from this decomposition are then concatenated with adjacent normal string literals (or those produced by adjacent f-strings). Finally, the equally new BUILD_STRING
opcode is used to join the pieces efficiently. Note that this means that your two format
functions compile to identical bytecode and any timing differences are just noise.
From this (implementor’s) perspective, the rules are obvious; from the user’s perspective, formatting occurs, intuitively, only inside f"…"
. It’s a matter of taste whether to write f"v={{{x},{y}}}\n"
or "v={" f"{x},{y}" "}\n"
, but I can certainly conceive of cases where the latter would be preferable. So long as you’re willing to point people to this question if they have doubts about the semantics, I’d say that’s enough to make the half-opinion answer “yes, it’s OK”.