F-Strings VS Str.Format()

f-strings vs str.format()

I'm afraid that it will be deprecated during the next Python versions

Don't be, str.format does not appear (nor has a reason) to be leaving any time soon, the PEP that introduced fprefixed-strings even states in its Abstract:

This PEP does not propose to remove or deprecate any of the existing string formatting mechanisms.

Formatted strings were introduced to address some of the shortcomings other methods for formatting strings had; not to throw the old methods away and force god-knows how many projects to use f-string's if they want their code to work for Python 3.6+.


As for the performance of these, it seems my initial suspicion that they might be slower is wrong, f-strings seem to easily outperform their .format counterparts:

➜ cpython git:(master) ./python -m timeit -s "a = 'test'" "f'formatting a string {a}'"
500000 loops, best of 5: 628 nsec per loop
➜ cpython git:(master) ./python -m timeit "'formatting a string {a}'.format(a='test')"
100000 loops, best of 5: 2.03 usec per loop

These were done against the master branch of the CPython repository as of this writing; they are definitely subject to change:

  • f-strings, as a new feature, might have possible optimizations
  • Optimizations to CPython might make .format faster (e.g Speedup method calls 1.2x)

But really, don't worry about speed so much, worry about what is more readable to you and to others.

In many cases, that's going to be f-strings, but there's some cases where format is better.

f-string representation different than str()

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 = 'something\n nasty!'
>>> error_message = f"Key not found: {key!r}"
>>> error_message
"Key not found: 'something\\n nasty!'"

What's the difference between f{x} and {}.format(x) in python?

Python f-strings were added in 3.6. Therefore you should consider using format() if you need compatibility with earlier versions. Otherwise, use f-strings.

On macOS 12.1 running 3 GHz 10-Core Intel Xeon W and Python 3.10.2, f-strings are significantly faster (~60%)

String formatting: % vs. .format vs. f-string literal

To answer your first question... .format just seems more sophisticated in many ways. An annoying thing about % is also how it can either take a variable or a tuple. You'd think the following would always work:

"Hello %s" % name

yet, if name happens to be (1, 2, 3), it will throw a TypeError. To guarantee that it always prints, you'd need to do

"Hello %s" % (name,)   # supply the single argument as a single-item tuple

which is just ugly. .format doesn't have those issues. Also in the second example you gave, the .format example is much cleaner looking.

Only use it for backwards compatibility with Python 2.5.


To answer your second question, string formatting happens at the same time as any other operation - when the string formatting expression is evaluated. And Python, not being a lazy language, evaluates expressions before calling functions, so the expression log.debug("some debug info: %s" % some_info) will first evaluate the string to, e.g. "some debug info: roflcopters are active", then that string will be passed to log.debug().

Is there a difference between f and F in Python string formatting?

As explained in the PEP 498, chapter Specification, both are accepted, and should not differ.

In source code, f-strings are string literals that are prefixed by the letter 'f' or 'F'. Everywhere this PEP uses 'f', 'F' may also be used.

Why are f-strings faster than str() to parse values?

The simple answer is because f-strings are part of the language's grammar and syntax. The str() call on the other hand requires a symbol table lookup, followed by a function call.

Here's a similar example which interpolates an integer variable, contrast this with the constant value interpolation.

x = 1

%timeit f'{1}'
%timeit f'{x}'
%timeit str(1)
%timeit str(x)

113 ns ± 2.25 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
166 ns ± 4.71 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
342 ns ± 23.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
375 ns ± 11.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

The difference in the behaviour is obvious when you look at the disassembled byte code with dis.

import dis

dis.dis("f'{x}'")
1 0 LOAD_NAME 0 (x)
2 FORMAT_VALUE 0
4 RETURN_VALUE

dis.dis("str(x)")
1 0 LOAD_NAME 0 (str)
2 LOAD_NAME 1 (x)
4 CALL_FUNCTION 1
6 RETURN_VALUE

The heavy lifting is all in the CALL_FUNCTION instruction, an overhead which f-strings certainly don't have -- at least in this case, as nothing needs to be eval'd.



Related Topics



Leave a reply



Submit