String formatting with f-strings
F-strings are one of the most beloved new Python features that came with Python 3.6. It's also one of the most controversial features of that release. The f-strings or formatted string literals that were introduced by the PEP 498 document add a new way to format strings in Python. Before Python 3.6, there were two basic ways to format strings:
- Using % formatting for example "Some string with included % value" % "other"
- Using the str.format() method for example "Some string with included {other} value".format(other="other")
Formatted string literals are denoted with the f prefix, and their syntax is closest to the str.format() method, as they use a similar markup for denoting replacement fields in the text that has to be formatted. In the str.format() method, the text substitutions refer to arguments and keyword arguments that are passed to the formatting method. You can use either anonymous substitutions that will translate to consecutive argument indexes, explicit argument indexes, or keyword names.
This means that the same string can be formatted in different ways:
>>> from sys import version_info
>>> "This is Python {}.{}".format(*version_info)
'This is Python 3.7'
>>> "This is Python {0}.{1}".format(*version_info)
'This is Python 3.7'
>>> "This is Python {major}.{minor}".format(major=version_info.major, minor=version_info.minor)
'This is Python 3.7'
What makes f-strings special is that replacement fields can be any Python expression, and it will be evaluated at runtime. Inside of strings, you have access to any variable that is available in the same namespace as the formatted literal. With f-strings, the preceding examples could be written in the following way:
>>> from sys import version_info
>>> f"This is Python {version_info.major}.{version_info.minor}"
'This is Python 3.7'
The ability to use expressions as replacement fields make formatting code simpler and shorter. You can also use the same formatting specifiers of replacement fields (for padding, aligning, signs, and so on) as the str.format() method, and the syntax is as follows:
f"{replacement_field_expression:format_specifier}"
The following is a simple example of code that prints the first ten powers of the number 10 using f-strings and aligns results using string formatting with padding:
>>> for x in range(10):
... print(f"10^{x} == {10**x:10d}")
...
10^0 == 1
10^1 == 10
10^2 == 100
10^3 == 1000
10^4 == 10000
10^5 == 100000
10^6 == 1000000
10^7 == 10000000
10^8 == 100000000
10^9 == 1000000000
The full formatting specification of the Python string is almost like a separate mini-language inside Python. The best reference for it is the official documentation which you can find under https://docs.python.org/3/library/string.html. Another useful internet resource for that topic is https://pyformat.info/, which presents the most important elements of this specification using practical examples.
Let's take a look at containers in the next section.