All currently supported Python versions (3.6+) support string-formatting via f-strings. While PEP 498 (Literal String Interpolation) as well as the Python documention (tutorial, syntax reference) have some information on their usage, I was missing a reference which is terse, but still verbose enough to explain the syntax.
Thus, fstring.help was born, made with and
(initially as a quick hack at PyConDE 2022).
Created by
Trainings, coaching and development for pytest, Qt and other Python/development topics.
Some content is copied verbatim from pyformat.info (Copyright 2015 Ulrich Petri, Horst Gutmann). Thanks!
Cheat sheet tables can be found at fstring.help/cheat thanks to Trey Hunner.
Repository on Github, contributions welcome! If you prefer an interactive version, .
f-strings are strings with an f
in front of them: f"..."
or f'...'
. Inside the f-string, curly braces can be used to format values into it:
one = 1
two = 2
f"{one}, {two}"
'1, 2'
You can put any Python code into f-strings:
f"{one} + {two} = {one + two}"
'1 + 2 = 3'
This can also be used to access dictionary entries:
colors = {
"red": "#ff0000",
"green": "#00ff00",
"blue": "#0000ff",
}
f"red: {colors['red']}"
'red: #ff0000'
Similarly, you can access list items:
data = [4, 8, 15, 16, 23, 42]
f"Best numbers: {data[4]} and {data[5]}"
'Best numbers: 23 and 42'
Or attributes:
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
pos = Point(23, 42)
f"{pos.x}, {pos.y}"
'23, 42'
Or even call functions:
f"bigger value: {max(pos.x, pos.y)}"
'bigger value: 42'
Note, however, that this should be used with care: Complex expressions are better first assigned to a variable.
Python 3.8 added support for self-documenting expressions and debugging - some examples adapted from the "what's new" document:
from datetime import date
user = "eric_idle"
member_since = date(1975, 7, 31)
delta = date(2022, 4, 11) - member_since
f"{user=} {member_since=}"
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"
The usual f-string format specifiers (see below) allow more control over how the result of the expression is displayed:
f"{user=!s} {delta.days=:,d}"
'user=eric_idle delta.days=17,056'
Whitespace around the =
is preserved in the output:
f"{user = }"
"user = 'eric_idle'"
The whole expression is displayed, so that calculations can be shown:
from math import cos, radians
theta = 30
f"{theta=} {cos(radians(theta))=:.3f}"
'theta=30 cos(radians(theta))=0.866'
Since f-strings support running any code, just call repr(...)
on your object:
class Data:
def __repr__(self):
return '<Data ...>'
def __str__(self):
return 'string representation'
data = Data()
f"data: {data}"
'data: string representation'
f"data: {repr(data)}"
'data: <Data ...>'
Alternatively, use the !r
suffix like with .format()
:
f"data: {data!r}"
'data: <Data ...>'
An !s
suffix to convert to a string explicitly is also supported, though often not needed (as this is the default behavior in most cases):
f"data: {data!s}"
'data: string representation'
val = "test"
f"{val:>10}"
' test'
Align left:
f"{val:<10}"
'test '
You are able to choose the padding character:
f"{val:_<10}"
'test______'
And also center align values:
f"{val:^10}"
' test '
By default, strings are left-aligned:
f"{val:10}"
'test '
but numbers are right-aligned:
answer = 42
f"{answer:10}"
' 42'
When using center alignment, where the length of the string leads to an uneven split of the padding characters, the extra character will be placed on the right side:
archive = 'zip'
f"{archive:^6}"
' zip '
Inverse to padding, it is also possible to truncate overly long values to a specific number of characters.
The number behind a .
in the format specifies the precision of the output. For strings, that means that the output is truncated to the specified length. In our example, this would be 5 characters.
instrument = "xylophone"
f"{instrument:.5}"
'xylop'
It is also possible to combine truncating and padding:
f"{instrument:10.5}"
'xylop '
Integers:
answer = 42
f"{answer:d}"
'42'
Floats:
import math
f"{math.pi:f}"
'3.141593'
Numbers can also be represented in other bases, such as octal:
f"{answer:o}"
'52'
hexadecimal (lower- or uppercase):
f"{answer:x}, {answer:X}"
'2a, 2A'
or binary:
f"{answer:b}"
'101010'
A #
can be used to add a suitable prefix (0o
, 0x
and 0b
, respectively):
f"{answer:#x}"
'0x2a'
Some other representations are available too, such as converting the number into an unicode character:
f"{answer:c}"
'*'
displaying it in scientific notation (E
instead of e
for uppercase):
f"{answer ** 8:e}"
'9.682652e+12'
or selecting scientific notation automatically for larger numbers (G
instead of g
for uppercase):
f"{answer:g}, {answer ** 8:g}"
'42, 9.68265e+12'
Similar to strings, numbers can also be constrained to a specific width.
f"{answer:4d}"
' 42'
Like for strings, the padding character can be selected:
f"{answer:04d}"
'0042'
Again similar to truncating strings, the precision for floating point numbers limits the number of positions after the decimal point.
For floating points, the padding value represents the length of the complete output. In the example below, we want our output to have at least 6 characters, with 2 after the decimal point.
f"{math.pi:06.2f}"
'003.14'
For integer values, providing a precision doesn't make much sense and results in a ValueError:
f"{answer:06.2d}"
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Input In [50], in <cell line: 1>() ----> 1 f"{answer:06.2d}" ValueError: Precision not allowed in integer format specifier
By default, only negative numbers are prefixed with a sign. This can be changed of course.
f"{answer:+d}"
'+42'
Use a space character to indicate that negative numbers should be prefixed with a minus symbol and a leading space should be used for positive ones.
f"{answer: d}"
' 42'
f"{-answer: d}"
'-42'
It's also possible to control the position of the sign symbol relative to the padding.
f"{-answer:=5d}"
'- 42'
f"{answer:=+5d}"
'+ 42'
It's possible to use either ,
or _
as a thousands separator when displaying large numbers:
num = 1234567890
f"{num:d}"
'1234567890'
f"{num:,d}"
'1,234,567,890'
f"{num:_d}"
'1_234_567_890'
Like .format()
, f-strings also allow objects to control their own rendering. This for example allows datetime objects to be formatted inline:
from datetime import datetime
dt = datetime(2022, 4, 11, 13, 37)
f"{dt:%Y-%m-%d %H:%M}"
'2022-04-11 13:37'
Additionally, f-strings allow all of the components of the format to be specified dynamically using parametrization. Parametrized formats are nested expressions in braces that can appear anywhere in the parent format after the colon.
Parametrized alignment and width:
value = "test"
align = "^"
width = 10
f'{value:{align}{width}}'
' test '
Parametrized precision:
value = "pizza"
prec = 2
f"{value:.{prec}} = {math.pi:.{prec}f}"
'pi = 3.14'
Width and precision:
width = 5
f"{math.pi:{width}.{prec}f}"
' 3.14'
The components of a date-time can be set separately:
dfmt = "%Y-%m-%d"
tfmt = "%H:%M"
f"{dt:{dfmt} {tfmt}}"
'2022-04-11 13:37'
The datetime example works through the use of the __format__()
magic method. You can define custom format handling in your own objects by overriding this method. This gives you complete control over the format syntax used.
class HAL9000:
def __format__(self, fmt):
if fmt == "open-the-pod-bay-doors":
return "I'm afraid I can't do that."
return "HAL 9000"
hal9000 = HAL9000()
f"{hal9000:open-the-pod-bay-doors}"
"I'm afraid I can't do that."
To use {
or }
inside an f-string, double them:
f"Literal braces: {{value}}"
'Literal braces: {value}'
Starting with Python 3.12, nested quotes (as well as backslashes) are freely allowed inside of {...}
in an f-string (PEP 701 – Syntactic formalization of f-strings).
For Python versions before 3.12, if you need to use single quotes inside an f-string, the easiest way is to use double-quotes for the string (and vice-versa), like with ordinary strings:
f"I'm an fstring"
f'"Use fstrings", he said!'
'"Use fstrings", he said!'
If you need to use single and double-quotes in the string, escape one of them - again, like with regular strings:
f"The string above contains: \"I'm an fstring\""
'The string above contains: "I\'m an fstring"'
Things get a bit more troublesome when mixing quotes inside replacements: There, backslashes are not allowed. Usually, you can just use the other kind of string quotes, like we did in an earlier example:
f"red: {colors['red']}"
'red: #ff0000'
Using the same quotes would end the string:
f"red: {colors["red"]}" # WRONG
Input In [76] f"red: {colors["red"]}" # WRONG ^ SyntaxError: f-string: unmatched '['
And backslashes won't work either:
f"red: {colors[\"red\"]}" # WRONG
Input In [77] f"red: {colors[\"red\"]}" # WRONG ^ SyntaxError: f-string expression part cannot include a backslash
But triple-quotes work great:
f"""red: {colors["red"]}"""
Or you can use a temporary variable instead.