f-Strings are a way of formatting your strings. It’s not the only way to do this in Python, but it’s the most powerful.
An f-string is created by appending the letter “f” to the front of a string and then adding the name of an already-defined variable between curly bracket. The value of that variable will then get incorporated into the string itself.
answer = 10
print(f'The answer is {answer}')
## The answer is 10
Multiple arguments can be incorporated into an f-string, and these can be either numbers or strings:
first = 47
second = 'hi'
print(f'First argument: {first}, second one: {second}')
## First argument: 47, second one: hi
Adding an equals sign will print the variable name as well (which is useful for debugging):
foo = 81
bar = 'hello'
print(f'First argument: {foo=}, second one: {bar=}')
## First argument: foo=81, second one: bar='hello'
For simple variables, an f-string is identical to just printing two things side-by-side:
answer = 10
# A normal string literal
print('The answer is', answer)
# An f-string
print(f'The answer is {answer}')
## The answer is 10
## The answer is 10
However, for more complicated examples, f-strings will start to get more convenient than just printing. Let’s take a closer look at how to use them:
If you print a number using an f-string without any formatting it might not always look good:
answer = 1/3
print(f'Very long answer: {answer}')
## Very long answer: 0.3333333333333333
To fix this, you’ll first need to choose a number format followed by width and decimal place options:
A first step to having better-looking numerical outputs is to format your numbers using one of the following built-in options:
A formatting option is used by placing a colon immediately after the variable name followed by the character corresponding to your chosen option:
answer = 123
print(f'd = decimal: {answer:d}')
answer = 123.123
print(f'f = fixed-point: {answer:f}')
print(f'e = exponential: {answer:e}')
print(f'g = general: {answer:g}')
print(f'% = percentage: {answer:%}')
## d = decimal: 123
## f = fixed-point: 123.123000
## e = exponential: 1.231230e+02
## g = general: 123.123
## % = percentage: 12312.300000%
The width of a number, ie how many characters-worth of space it takes up, is specified by placing a number between the colon and the formatting option.
answer = 123
print(f'd = decimal: |{answer:1d}|{answer:9d}|{answer:15d}|')
answer = 123.123
print(f'f = fixed-point: |{answer:1f}|{answer:9f}|{answer:15f}|')
print(f'e = exponential: |{answer:1e}|{answer:9e}|{answer:15e}|')
print(f'g = general: |{answer:1g}|{answer:9g}|{answer:15g}|')
print(f'% = percentage: |{answer:1%}|{answer:9%}|{answer:15%}|')
## d = decimal: |123| 123| 123|
## f = fixed-point: |123.123000|123.123000| 123.123000|
## e = exponential: |1.231230e+02|1.231230e+02| 1.231230e+02|
## g = general: |123.123| 123.123| 123.123|
## % = percentage: |12312.300000%|12312.300000%| 12312.300000%|
The number of digits that get displayed after the decimal point can be specified by placing a full stop and the desired number between the width and the format options:
answer = 123.123
print(f'f = fixed-point: |{answer:15.1f}|{answer:15.3f}|{answer:15.5f}|')
print(f'e = exponential: |{answer:15.1e}|{answer:15.3e}|{answer:15.5e}|')
print(f'g = general: |{answer:15.1g}|{answer:15.3g}|{answer:15.5g}|')
print(f'% = percentage: |{answer:15.1%}|{answer:15.3%}|{answer:15.5%}|')
## f = fixed-point: | 123.1| 123.123| 123.12300|
## e = exponential: | 1.2e+02| 1.231e+02| 1.23123e+02|
## g = general: | 1e+02| 123| 123.12|
## % = percentage: | 12312.3%| 12312.300%| 12312.30000%|
For obvious reasons, the decimal place modifier cannot be used with the “d” formatting option. Similarly, specifying more decimal places than the width will allow will be corrected by Python.
Fully format a numerical f-string with:
{VariableName:Width.DecimalsFormat}
Usually, negative numbers are shown like this:
answer = -123
print(f'd = decimal: |{answer:15d}|')
answer = -123.123
print(f'f = fixed-point: |{answer:15.1f}|{answer:15.3f}|{answer:15.5f}|')
print(f'e = exponential: |{answer:15.1e}|{answer:15.3e}|{answer:15.5e}|')
print(f'g = general: |{answer:15.1g}|{answer:15.3g}|{answer:15.5g}|')
print(f'% = percentage: |{answer:15.1%}|{answer:15.3%}|{answer:15.5%}|')
## d = decimal: | -123|
## f = fixed-point: | -123.1| -123.123| -123.12300|
## e = exponential: | -1.2e+02| -1.231e+02| -1.23123e+02|
## g = general: | -1e+02| -123| -123.12|
## % = percentage: | -12312.3%| -12312.300%| -12312.30000%|
To force the padding to be applied after the minus sign, prepend an equals sign to the formatting modifier:
answer = -123
print(f'd = decimal: |{answer:=15d}|')
answer = -123.123
print(f'f = fixed-point: |{answer:=15.1f}|{answer:=15.3f}|{answer:=15.5f}|')
print(f'e = exponential: |{answer:=15.1e}|{answer:=15.3e}|{answer:=15.5e}|')
print(f'g = general: |{answer:=15.1g}|{answer:=15.3g}|{answer:=15.5g}|')
print(f'% = percentage: |{answer:=15.1%}|{answer:=15.3%}|{answer:=15.5%}|')
## d = decimal: |- 123|
## f = fixed-point: |- 123.1|- 123.123|- 123.12300|
## e = exponential: |- 1.2e+02|- 1.231e+02|- 1.23123e+02|
## g = general: |- 1e+02|- 123|- 123.12|
## % = percentage: |- 12312.3%|- 12312.300%|- 12312.30000%|
To show a sign regardless of whether the number is positive or negative, use the plus sign:
answer = -123
print(f'd = decimal: |{answer:+15d}|')
answer = 123.123
print(f'f = fixed-point: |{answer:+15.1f}|{answer:+15.3f}|{answer:+15.5f}|')
print(f'e = exponential: |{answer:+15.1e}|{answer:+15.3e}|{answer:+15.5e}|')
print(f'g = general: |{answer:+15.1g}|{answer:+15.3g}|{answer:+15.5g}|')
print(f'% = percentage: |{answer:+15.1%}|{answer:+15.3%}|{answer:+15.5%}|')
## d = decimal: | -123|
## f = fixed-point: | +123.1| +123.123| +123.12300|
## e = exponential: | +1.2e+02| +1.231e+02| +1.23123e+02|
## g = general: | +1e+02| +123| +123.12|
## % = percentage: | +12312.3%| +12312.300%| +12312.30000%|
To combine the above two and show the padding after the positive/negative sign, regardless of whether the number is positive or negative, use both an equals sign and a plus sign:
answer = -123
print(f'd = decimal: |{answer:=+15d}|')
answer = 123.123
print(f'f = fixed-point: |{answer:=+15.1f}|{answer:=+15.3f}|{answer:=+15.5f}|')
print(f'e = exponential: |{answer:=+15.1e}|{answer:=+15.3e}|{answer:=+15.5e}|')
print(f'g = general: |{answer:=+15.1g}|{answer:=+15.3g}|{answer:=+15.5g}|')
print(f'% = percentage: |{answer:=+15.1%}|{answer:=+15.3%}|{answer:=+15.5%}|')
## d = decimal: |- 123|
## f = fixed-point: |+ 123.1|+ 123.123|+ 123.12300|
## e = exponential: |+ 1.2e+02|+ 1.231e+02|+ 1.23123e+02|
## g = general: |+ 1e+02|+ 123|+ 123.12|
## % = percentage: |+ 12312.3%|+ 12312.300%|+ 12312.30000%|
Show leading zeros by prepending 0
to the formatting modifier:
answer = 123
print(f'd = decimal: |{answer:015d}|')
answer = 123.123
print(f'f = fixed-point: |{answer:015.1f}|{answer:015.3f}|{answer:015.5f}|')
print(f'e = exponential: |{answer:015.1e}|{answer:015.3e}|{answer:015.5e}|')
print(f'g = general: |{answer:015.1g}|{answer:015.3g}|{answer:015.5g}|')
print(f'% = percentage: |{answer:015.1%}|{answer:015.3%}|{answer:015.5%}|')
## d = decimal: |000000000000123|
## f = fixed-point: |0000000000123.1|00000000123.123|000000123.12300|
## e = exponential: |000000001.2e+02|0000001.231e+02|00001.23123e+02|
## g = general: |00000000001e+02|000000000000123|000000000123.12|
## % = percentage: |000000012312.3%|0000012312.300%|00012312.30000%|
Have a thousands separator by using a comma in the formatting modifier:
answer = 123456789.123
print(f'Thousands separator: |{answer:,.2f}|')
## Thousands separator: |123,456,789.12|
Strings are handled similarly to numbers, although they are less complex. Strings are indicated with the “s” formatting option:
first = 'Hello'
second = 'World'
print(f'Simple: |{first:s}|{second:s}|')
## Simple: |Hello|World|
Specifying a width can create padding (note that strings are left-aligned by default, whereas numbers are right-aligned):
print(f'Padding: |{first:20s}|{second:10s}|')
## Padding: |Hello |World |
Specifying a ‘precision’ will truncate the string:
print(f'Truncating: |{first:.2s}|{second:.3s}|')
## Truncating: |He|Wor|
Of course, truncating and padding can be combined:
print(f'Truncating & padding: |{first:15.2s}|{second:10.3s}|')
## Truncating & padding: |He |Wor |
A number can always be converted to a string using the str()
function. There may be some circumstances where that helps you with formatting:
answer = 1234
print(f'A number: {str(answer)}')
## A number: 1234
However, this conversion from number to string can actually be done automatically by an f-string using “!s”:
print(f'Call str() using !s: |{answer!s}|')
print(f'Call str() using !s, with padding: |{answer!s:6}|')
## Call str() using !s: |1234|
## Call str() using !s, with padding: |1234 |
This works for Booleans too:
first = True
second = False
print(f'Call str() on Booleans: |{first!s:8}|{second!s:8}|')
## Call str() on Booleans: |True |False |
Things such as datetime
objects can also be formatted within the curly brackets of an f-string. Here’s an example of a normal (unformatted) datetime
object (more info about these can be found on the Date and Time page):
from datetime import datetime
dt = datetime(2012, 3, 4, 5, 6, 7)
print(dt)
## 2012-03-04 05:06:07
These can be formatted by adding a date format code as a string after the colon:
dt = datetime(2012, 3, 4, 5, 6, 7)
print(f'{dt:%Hh%M on %d %B %Y}')
## 05h06 on 04 March 2012
For more info about date format codes, see the documentation here.
By default, strings get left-aligned and numbers get right-aligned. This can be controlled explicitly by using the “<”, “>” and “^” characters:
first = 'String'
second = 123.456
print(f'Default: |{first:16s}|{second:16.2f}|')
print(f'Left: |{first:<16s}|{second:<16.2f}|')
print(f'Right: |{first:>16s}|{second:>16.2f}|')
print(f'Centred: |{first:^16s}|{second:^16.2f}|')
## Default: |String | 123.46|
## Left: |String |123.46 |
## Right: | String| 123.46|
## Centred: | String | 123.46 |
You can format an entire list of objects by using a combination of f-strings, list comprehension and the .join()
method:
ls = [
6.28318,
2.71828,
0.57721,
9.81,
6.67430,
]
# The formatter ".0f" will round to the nearest whole number
print('\n'.join(f'{v:.0f}' for v in ls))
## 6
## 3
## 1
## 10
## 7
The general form of a standard format specifier is:
[[fill]align][sign][#][0][width][,][.precision][type]
Take a look at the explanatory table below or here for more details.
Field | Description | Values | Default |
---|---|---|---|
fill | What character to fill ‘white space’ padding with | Any character | Space |
align | Align the object left, right or centrally | “<”, “>”, “=”, “^” | “<” (strings), “>” (numbers) |
sign | How positives, negatives, bases and thousands get treated | “+”, “-”, " “,”#“,”," | “-” |
width | The minimum field width | Any positive integer | The variable’s width |
precision | How many digits should be displayed after the decimal point/how long the string must be | Any positive integer | The precision of the number/length of the string |
type | How the data should be presented | “b”, “c”, “d”, “e”, “E”, “f”, “F”, “g”, “G”, “n”, “o”, “s”, “x”, “X”, “%” | “s”, “d”, “g” |